Існують 3 типові методи, які визначають, чи може користувач бачити HTML-сторінку, проте жоден з них не працює ідеально:
W3C Page Visibility API повинен робити це (підтримується починаючи з: Firefox 10, MSIE 10, Chrome 13). Однак цей API викликає події лише тоді, коли вкладку браузера повністю перекрито (наприклад, коли користувач переходить з однієї вкладки на іншу). API не викликає подій, коли видимість неможливо визначити зі 100% точністю (наприклад, Alt + Tab для переходу на іншу програму).
Використання методів, орієнтованих на фокусування / розмиття, дає вам багато хибних позитивів. Наприклад, якщо користувач відображає менше вікно вгорі вікна браузера, вікно браузера втрачає фокус ( onblur
піднятий), але користувач все одно може бачити його (тому його все одно потрібно оновити). Дивіться також http://javascript.info/tutorial/focus
- Опираючись на активність користувача (переміщення миші, клацання, введення клавіш), дає вам також багато хибних позитивних результатів. Подумайте про той самий випадок, як вище, або про користувача, який переглядає відео.
Для покращення описаної вище недосконалої поведінки я використовую комбінацію трьох методів: API видимості W3C, потім фокусування / розмиття та методи діяльності користувачів, щоб зменшити помилкову позитивну швидкість. Це дозволяє керувати такими подіями:
- Зміна вкладки браузера на іншу (100% точність завдяки API видимості сторінки W3C)
- Сторінка потенційно прихована іншим вікном, наприклад, через Alt + Tab (імовірнісна = не на 100% точна)
- Увага користувачів потенційно не зосереджена на HTML-сторінці (вірогідна = не на 100% точність)
Так це працює: коли документ втрачає фокус, активність користувача (наприклад, переміщення миші) на документі відстежується, щоб визначити, вікно видно чи ні. Ймовірність видимості сторінки обернено пропорційна часу останньої активності користувача на сторінці: якщо користувач довго не здійснює жодної активності в документі, сторінка, ймовірно, не видно. Код нижче імітує API видимості сторінки W3C: він поводиться так само, але має невелику помилкову позитивну швидкість. Вона має перевагу в тому, що вона є мультисекреторною (тестується на Firefox 5, Firefox 10, MSIE 9, MSIE 7, Safari 5, Chrome 9).
<div id = "x"> </div>
<script>
/ **
Реєструє обробник події для даного об'єкта.
@param obj об'єкт, який підніме подію
@param evВведіть тип події: клацання, натискання клавіші, наведення миші, ...
@param fn функція обробника подій
@param isCapturing встановити режим події (true = захоплення події, false = подія барботажу)
@return вірно, якщо обробник подій був прикріплений правильно
* /
функція addEvent (obj, evType, fn, isCapturing) {
if (isCapturing == null) isCapturing = false;
якщо (obj.addEventListener) {
// Firefox
obj.addEventListener (evType, fn, isCapturing);
повернути правду;
} else if (obj.attachEvent) {
// MSIE
var r = obj.attachEvent ('on' + evType, fn);
повернути r;
} else {
повернути помилкове;
}
}
// зареєструватися на потенційній зміні видимості сторінки
addEvent (документ, "потенційна зміна змін", функція (подія) {
document.getElementById ("x"). innerHTML + = "potencialVisilityChange: potencialHidden =" + document.potentialHidden + ", document.potentialHiddenSince =" + document.potentialHiddenSince + "s <br>";
});
// зареєструватися в API видимості сторінки W3C
var схований = null;
var visibilityChange = null;
if (typeof document.mozHidden! == "undefined") {
прихований = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if (typeof document.msHidden! == "undefined") {
приховано = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden! == "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
} else if (typeof document.hidden! == "приховано") {
hidden = "приховано";
visibilityChange = "видимістьзмінити";
}
if (приховано! = null && visibilityChange! = null) {
addEvent (документ, видимістьЗміни, функція (подія) {
document.getElementById ("х"). innerHTML + = visibilityChange + ":" + прихований + "=" + документ [приховано] + "<br>";
});
}
var потенціалPageVisibility = {
pageVisibilityChangeThreshold: 3 * 3600, // за секунди
init: function () {
набір функційAsNotHidden () {
var dispatchEventRequired = document.potentialHidden;
document.potentialHidden = хибний;
документ.потенційноHiddenSince = 0;
if (dispatchEventRequired) dispatchPageVisibilityChangeEvent ();
}
функція initPotenicallyHiddenDetection () {
if (! hasFocusLocal) {
// у вікні немає фокуса => перевірка активності користувача у вікні
lastActionDate = нова дата ();
якщо (timeoutHandler! = null) {
clearTimeout (timeoutHandler);
}
timeoutHandler = setTimeout (checkPageVisibility, potencijalPageVisibility.pageVisibilityChangeThreshold * 1000 + 100); // +100 мс, щоб уникнути проблем із округленням у Firefox
}
}
функція dispatchPageVisibilityChangeEvent () {
unifiedVisilityChangeEventDispatchAllowed = false;
var evt = document.createEvent ("Подія");
evt.initEvent ("зміна потенційної стійкості", істина, істина);
document.dispatchEvent (evt);
}
функція checkPageVisibility () {
var потенціалHiddenDuration = (hasFocusLocal || lastActionDate == null? 0: Math.floor ((нова дата (). getTime () - lastActionDate.getTime ()) / 1000));
документ.потенційноHiddenSince = потенціалHiddenDuration;
if (potencijalHiddenDuration> = potencijalPageVisibility.pageVisibilityChangeThreshold &&! document.potentialHidden) {
// Поріг зміни видимості сторінки raiched => підвищити рівний
document.potentialHidden = вірно;
dispatchPageVisibilityChangeEvent ();
}
}
var lastActionDate = null;
var hasFocusLocal = true;
var hasMouseOver = вірно;
document.potentialHidden = хибний;
документ.потенційноHiddenSince = 0;
var timeoutHandler = null;
addEvent (документ, "показ сторінки", функція (подія) {
document.getElementById ("x"). innerHTML + = "pageshow / doc: <br>";
});
addEvent (документ, "pagehide", функція (подія) {
document.getElementById ("х"). innerHTML + = "pagehide / doc: <br>";
});
addEvent (вікно, "показ сторінок", функція (подія) {
document.getElementById ("х"). innerHTML + = "сторінку show / win: <br>"; // піднімається, коли сторінка відображається вперше
});
addEvent (вікно, "pagehide", функція (подія) {
document.getElementById ("х"). innerHTML + = "pagehide / win: <br>"; // не піднятий
});
addEvent (документ, "переміщення миші", функція (подія) {
lastActionDate = нова дата ();
});
addEvent (документ, "перехід миші", функція (подія) {
hasMouseOver = true;
setAsNotHidden ();
});
addEvent (документ, "миші", функція (подія) {
hasMouseOver = false;
initPotenicallyHiddenDetection ();
});
addEvent (вікно, "розмиття", функція (подія) {
hasFocusLocal = хибний;
initPotenicallyHiddenDetection ();
});
addEvent (вікно, "фокус", функція (подія) {
hasFocusLocal = вірно;
setAsNotHidden ();
});
setAsNotHidden ();
}
}
potencijalPageVisibility.pageVisibilityChangeThreshold = 4; // 4 секунди для тестування
potencijalPageVisibility.init ();
</script>
Оскільки в даний час не існує робочого крос-браузерного рішення без помилкового позитиву, вам слід подумати двічі про відключення періодичної активності на вашому веб-сайті.
requestAnimationFrame
API або використовуйте сучасну функцію, що частотаsetTimeout
/setInterval
зменшується, коли вікно не видно (наприклад, 1 сек у Chrome).