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


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.