Виявити, якщо вкладка браузера має фокус


149

Чи є надійний крос-браузерний спосіб виявити, що вкладка має фокус.

Сценарій полягає в тому, що у нас є програма, яка регулярно проводить опитування щодо цін на акції, і якщо на сторінці немає уваги, ми можемо зупинити опитування та врятувати всіх від шуму трафіку, тим більше, що люди шанують відкриття декількох вкладок з різними портфелями.

Є window.onblurі window.onfocusваріант для цього?


Відповіді:


127

Так, window.onfocusі window.onblurмає працювати для вашого сценарію:

http://www.thefutureoftheweb.com/blog/detect-browser-window-focus


3
Аспект onfocusin / onfocusout цього, а також примітка про те, щоб повідомити користувачеві, що ви призупинилися, - це справді хороші нотатки. Дякую.
Фентон

7
Зверніть увагу, що ви не можете розрізнити, що сторінка активна чи неактивна при завантаженні сторінки таким чином.
pimvdb

@SteveFenton - onfocusце крос-броусер, де події, про які ви згадали, є лише IE, я не можу зрозуміти, чому ви вважаєте це гарною запискою ..
vsync

1
@vsync - читати пов'язану статтю, ви побачите , що він використовує як «onfocusin» і «OnFocus».
Фентон

Не могли б ви хоча б згадати різницю між ними?
Ленар Хойт

53

Важливо редагувати: Ця відповідь застаріла. Після його написаннябуло введеноAPI видимості ( mdn , наприклад , spec ). Це кращий спосіб вирішити цю проблему.


var focused = true;

window.onfocus = function() {
    focused = true;
};
window.onblur = function() {
    focused = false;
};

AFAIK, focusі blurвсі підтримуються на ... все. (див. http://www.quirksmode.org/dom/events/index.html )


2
Лише невелике зауваження, з усіма цими рішеннями ви ризикуєте користувачем змінити вкладки до повного завантаження javascript, тим самим призначивши неправильне значення зосередженому. Не впевнений, що є хороший шлях для цього.
JayD3e

Посилання на оновлення - саме те, що я шукав. Дякуємо, що додали їх!
webLacky3rdClass

Питання полягає в конкретному виявленні того, чи є на сторінці фокус, який відрізняється від визначення того, чи відображається сторінка. Кілька сторінок можуть бути помітні одночасно (у різних вікнах), тоді як лише одна може мати фокус. Використовуйте будь-яку техніку, яка відповідає вашим потребам, але знайте різницю.
jaredjacobs

1
Це небезпечне рішення, оскільки це ризикує перемогти якогось іншого слухача подій у більшій програмі. Ви повинні слідувати замість цієї відповіді: stackoverflow.com/a/21935031/549503
mmmeff

51

Під час пошуку цієї проблеми я знайшов рекомендацію щодо використання API Visibility Page . Більшість сучасних браузерів підтримують цей API відповідно до Чи можу я використовувати: http://caniuse.com/#feat=pagevisibility .

Ось робочий приклад (отриманий з цього фрагмента ):

$(document).ready(function() {
  var hidden, visibilityState, visibilityChange;

  if (typeof document.hidden !== "undefined") {
    hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState";
  } else if (typeof document.msHidden !== "undefined") {
    hidden = "msHidden", visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState";
  }

  var document_hidden = document[hidden];

  document.addEventListener(visibilityChange, function() {
    if(document_hidden != document[hidden]) {
      if(document[hidden]) {
        // Document hidden
      } else {
        // Document shown
      }

      document_hidden = document[hidden];
    }
  });
});

Оновлення: У наведеному вище прикладі використовувались префіксні властивості для веб-переглядачів Gecko та WebKit, але я її видалив, оскільки ці браузери вже деякий час пропонують API Visibility Page без префікса. Я зберігав специфічний префікс Майкрософт, щоб залишатися сумісним з IE10.


Коли від цього вийдуть префікси постачальника, я, мабуть, переключусь!
Фентон

Єдиною реальною проблемою у цьому є не префікси постачальника, оскільки існує офіційна рекомендація W3C (від 29 жовтня 2013 р.). Проблема в деяких випадках полягає в тому, що API видимості сторінки підтримується в IE10 та новіших версіях. Якщо вам потрібно підтримати IE9, вам слід шукати інший підхід…
Ілля,

Це правильний спосіб зробити це для всіх сучасних браузерів. +1
Ajedi32

Ви впевнені, що ці префікси постачальника навіть необхідні? Згідно з MDN та CanIUse, вони не потрібні в Chrome з версії 32 або в Firefox з версії 17, і вони ніколи не були потрібні в IE.
Ajedi32

@ Ajedi32 Дякую Мені потрібно зробити кілька тестів і копати, щоб побачити, що це все-таки актуально, і що зараз можна залишати.
Ілля

37

Дивно, коли ніхто не згадав document.hasFocus

if (document.hasFocus()) console.log('Tab is active')

MDN має більше інформації.


працює для мене (тестується на Chrome і Firefox). Прийнята відповідь (onfocus / onblur) не спрацювала
шкодить

Правильна відповідь ще раз у самому дні. Шлях пройти StackOverflow!
одинадцяте жовтня

насправді, чи не це ідеальна відповідь? хтось бачить недоліки?
gaspar

2
Єдиним недоліком цього є те, що якщо ви намагаєтеся визначити, чи вкладка знаходиться у фокусі зсередини iframe, то вона не вдасться у випадку завантаження iframe, коли батьківська сторінка все ще не була зосереджена. Для того, щоб висвітлити це, вам доведеться переглядати api видимості сторінки.
Іван

29

Так, вони повинні працювати на вас. Ви просто нагадали мені про це посилання, на яке я натрапив, що використовує ці методи. цікаве читання


2
+1 - це дуже розумний трюк, я міг уявити, що обдурює багато людей.
Фентон

2
Яка геніальна та хитра атака. Цікаво читайте, що, дякую.
Voo

4

Я зробив би це так (Довідка http://www.w3.org/TR/page-visibility/ ):

    window.onload = function() {

        // check the visiblility of the page
        var hidden, visibilityState, visibilityChange;

        if (typeof document.hidden !== "undefined") {
            hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState";
        }
        else if (typeof document.mozHidden !== "undefined") {
            hidden = "mozHidden", visibilityChange = "mozvisibilitychange", visibilityState = "mozVisibilityState";
        }
        else if (typeof document.msHidden !== "undefined") {
            hidden = "msHidden", visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState";
        }
        else if (typeof document.webkitHidden !== "undefined") {
            hidden = "webkitHidden", visibilityChange = "webkitvisibilitychange", visibilityState = "webkitVisibilityState";
        }


        if (typeof document.addEventListener === "undefined" || typeof hidden === "undefined") {
            // not supported
        }
        else {
            document.addEventListener(visibilityChange, function() {
                console.log("hidden: " + document[hidden]);
                console.log(document[visibilityState]);

                switch (document[visibilityState]) {
                case "visible":
                    // visible
                    break;
                case "hidden":
                    // hidden
                    break;
                }
            }, false);
        }

        if (document[visibilityState] === "visible") {
            // visible
        }

    };  

Чи можете ви пояснити, чим ця відповідь відрізняється від відповіді, наданої @Ilija - може бути різниця, але вона тонка - тому пояснюється, що це таке, і чому має бути іншим, було б вдячним.
Фентон

2

Рішення браузера jQuery! Сировина доступна в GitHub

Весело та просте у користуванні!

Наступний плагін пройде ваш стандартний тест для різних версій IE, Chrome, Firefox, Safari тощо. І відповідно встановить заявлені методи. Він також займається такими питаннями, як:

  • onblur | .blur / onfocus | .фокусувати " дублюючі " дзвінки
  • вікно втрачає фокус через вибір альтернативної програми, як слово
    • Це, як правило, небажано просто тому, що якщо у вас відкрита банківська сторінка, і це подія onblur сповіщає її замаскувати сторінку, то якщо ви відкриєте калькулятор, ви більше не можете бачити сторінку!
  • Не завантажується при завантаженні сторінки

Використовувати так само просто, як: Прокрутіть униз до " Виконати фрагмент "

$.winFocus(function(event, isVisible) {
    console.log("Combo\t\t", event, isVisible);
});

//  OR Pass False boolean, and it will not trigger on load,
//  Instead, it will first trigger on first blur of current tab_window
$.winFocus(function(event, isVisible) {
    console.log("Combo\t\t", event, isVisible);
}, false);

//  OR Establish an object having methods "blur" & "focus", and/or "blurFocus"
//  (yes, you can set all 3, tho blurFocus is the only one with an 'isVisible' param)
$.winFocus({
    blur: function(event) {
        console.log("Blur\t\t", event);
    },
    focus: function(event) {
        console.log("Focus\t\t", event);
    }
});

//  OR First method becoms a "blur", second method becoms "focus"!
$.winFocus(function(event) {
    console.log("Blur\t\t", event);
},
function(event) {
    console.log("Focus\t\t", event);
});

/*    Begin Plugin    */
;;(function($){$.winFocus||($.extend({winFocus:function(){var a=!0,b=[];$(document).data("winFocus")||$(document).data("winFocus",$.winFocus.init());for(x in arguments)"object"==typeof arguments[x]?(arguments[x].blur&&$.winFocus.methods.blur.push(arguments[x].blur),arguments[x].focus&&$.winFocus.methods.focus.push(arguments[x].focus),arguments[x].blurFocus&&$.winFocus.methods.blurFocus.push(arguments[x].blurFocus),arguments[x].initRun&&(a=arguments[x].initRun)):"function"==typeof arguments[x]?b.push(arguments[x]):
"boolean"==typeof arguments[x]&&(a=arguments[x]);b&&(1==b.length?$.winFocus.methods.blurFocus.push(b[0]):($.winFocus.methods.blur.push(b[0]),$.winFocus.methods.focus.push(b[1])));if(a)$.winFocus.methods.onChange()}}),$.winFocus.init=function(){$.winFocus.props.hidden in document?document.addEventListener("visibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="mozHidden")in document?document.addEventListener("mozvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden=
"webkitHidden")in document?document.addEventListener("webkitvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="msHidden")in document?document.addEventListener("msvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="onfocusin")in document?document.onfocusin=document.onfocusout=$.winFocus.methods.onChange:window.onpageshow=window.onpagehide=window.onfocus=window.onblur=$.winFocus.methods.onChange;return $.winFocus},$.winFocus.methods={blurFocus:[],blur:[],focus:[],
exeCB:function(a){$.winFocus.methods.blurFocus&&$.each($.winFocus.methods.blurFocus,function(b,c){this.apply($.winFocus,[a,!a.hidden])});a.hidden&&$.winFocus.methods.blur&&$.each($.winFocus.methods.blur,function(b,c){this.apply($.winFocus,[a])});!a.hidden&&$.winFocus.methods.focus&&$.each($.winFocus.methods.focus,function(b,c){this.apply($.winFocus,[a])})},onChange:function(a){var b={focus:!1,focusin:!1,pageshow:!1,blur:!0,focusout:!0,pagehide:!0};if(a=a||window.event)a.hidden=a.type in b?b[a.type]:
document[$.winFocus.props.hidden],$(window).data("visible",!a.hidden),$.winFocus.methods.exeCB(a);else try{$.winFocus.methods.onChange.call(document,new Event("visibilitychange"))}catch(c){}}},$.winFocus.props={hidden:"hidden"})})(jQuery);
/*    End Plugin      */

// Simple example
$(function() {
	$.winFocus(function(event, isVisible) {
		$('td tbody').empty();
		$.each(event, function(i) {
			$('td tbody').append(
				$('<tr />').append(
					$('<th />', { text: i }),
					$('<td />', { text: this.toString() })
				)
			)
		});
		if (isVisible) 
			$("#isVisible").stop().delay(100).fadeOut('fast', function(e) {
				$('body').addClass('visible');
				$(this).stop().text('TRUE').fadeIn('slow');
			});
		else {
			$('body').removeClass('visible');
			$("#isVisible").text('FALSE');
		}
	});
})
body { background: #AAF; }
table { width: 100%; }
table table { border-collapse: collapse; margin: 0 auto; width: auto; }
tbody > tr > th { text-align: right; }
td { width: 50%; }
th, td { padding: .1em .5em; }
td th, td td { border: 1px solid; }
.visible { background: #FFA; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h3>See Console for Event Object Returned</h3>
<table>
    <tr>
        <th><p>Is Visible?</p></th>
        <td><p id="isVisible">TRUE</p></td>
    </tr>
    <tr>
        <td colspan="2">
            <table>
                <thead>
                    <tr>
                        <th colspan="2">Event Data <span style="font-size: .8em;">{ See Console for More Details }</span></th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </td>
    </tr>
</table>


Ви повинні поставити код не мінімізований для плагіна.
Патрік Дежардінс

@PatrickDesjardins так. Плануйте робити це на ці вихідні разом з іншими речами. Я? Складіть суть за купу у мене речей. Jdmckinstry в Github. Додаватимуть посилання на старі відповіді на кшталт цих, коли я їх
додаю

Що робити, якщо я хочу, щоб сторінка втрачала фокус, коли я переходила на інший додаток, наприклад "Word" або "Калькулятор"?
Бенас

@Benas Можливо, помиляюся, але я вважаю, що це базовий функціонал самого базового jQuery(window).blur/focus, який багатьом був небажаний, тому одна з причин я зробив цей плагін. Плагін призначений допомогти забезпечити те, що jQuery ще не робить
SpYk3HH
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.