Ada 3 metode khas yang digunakan untuk menentukan apakah pengguna dapat melihat halaman HTML, namun tidak ada yang bekerja dengan sempurna:
The W3C Halaman Visibilitas API seharusnya melakukan hal ini (didukung sejak: Firefox 10, MSIE 10, Chrome 13). Namun, API ini hanya memunculkan peristiwa-peristiwa ketika tab browser sepenuhnya ditimpa (misalnya ketika pengguna berubah dari satu tab ke yang lain). API tidak memunculkan peristiwa ketika visibilitas tidak dapat ditentukan dengan akurasi 100% (misalnya Alt + Tab untuk beralih ke aplikasi lain).
Menggunakan metode fokus / blur memberi Anda banyak kesalahan positif. Misalnya, jika pengguna menampilkan jendela yang lebih kecil di atas jendela browser, jendela browser akan kehilangan fokus ( onblur
dinaikkan) tetapi pengguna masih dapat melihatnya (jadi masih perlu di-refresh). Lihat juga http://javascript.info/tutorial/focus
- Mengandalkan aktivitas pengguna (gerakan mouse, klik, ketikan kunci) memberi Anda banyak false positive juga. Pikirkan kasus yang sama seperti di atas, atau pengguna yang menonton video.
Untuk meningkatkan perilaku tidak sempurna yang dijelaskan di atas, saya menggunakan kombinasi dari 3 metode: W3C Visibility API, lalu fokus / blur dan metode aktivitas pengguna untuk mengurangi tingkat positif palsu. Ini memungkinkan untuk mengelola acara berikut:
- Mengubah tab browser ke yang lain (akurasi 100%, berkat W3C Page Visibility API)
- Halaman berpotensi disembunyikan oleh jendela lain, misalnya karena Alt + Tab (probabilitas = tidak 100% akurat)
- Perhatian pengguna berpotensi tidak terfokus pada halaman HTML (probabilitas = tidak 100% akurat)
Beginilah cara kerjanya: ketika dokumen kehilangan fokus, aktivitas pengguna (seperti gerakan mouse) pada dokumen dimonitor untuk menentukan apakah jendela terlihat atau tidak. Probabilitas visibilitas halaman berbanding terbalik dengan waktu aktivitas pengguna terakhir pada halaman: jika pengguna tidak membuat aktivitas pada dokumen untuk waktu yang lama, halaman kemungkinan besar tidak terlihat. Kode di bawah ini meniru API Visibilitas Halaman W3C: berperilaku dengan cara yang sama tetapi memiliki tingkat positif palsu yang kecil. Ini memiliki keuntungan menjadi multibrowser (diuji pada Firefox 5, Firefox 10, MSIE 9, MSIE 7, Safari 5, Chrome 9).
<div id = "x"> </div>
<script>
/ **
Mendaftarkan pawang ke acara untuk objek yang diberikan.
@param keberatan objek yang akan memunculkan acara
@param, ketikkan jenis acara: klik, tekan tombol, tetikus, ...
@param fn fungsi event handler
@param isCapturing mengatur mode acara (true = menangkap acara, false = acara menggelegak)
@ kembali benar jika pengendali acara telah terpasang dengan benar
* /
function addEvent (obj, evType, fn, isCapturing) {
if (isCapturing == null) isCapturing = false;
if (obj.addEventListener) {
// Firefox
obj.addEventListener (evType, fn, isCapturing);
kembali benar;
} lain jika (obj.attachEvent) {
// MSIE
var r = obj.attachEvent ('on' + evType, fn);
return r;
} lain {
return false;
}
}
// daftar ke perubahan visibilitas halaman potensial
addEvent (dokumen, "perubahan potensivisilitas", fungsi (acara) {
document.getElementById ("x"). innerHTML + = "potentialVisilityChange: potentialHidden =" + document.potentialHidden + ", document.potentialHiddenSince =" + document.potentialHiddenSince + "s <br>";
});
// daftar ke API Visibilitas Halaman W3C
var hidden = null;
var visibilityChange = null;
if (typeof document.mozHidden! == "undefined") {
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
} lain jika (typeof document.msHidden! == "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} lain jika (typeof document.webkitHidden! == "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
} lain jika (typeof document.hidden! == "disembunyikan") {
hidden = "hidden";
visibilityChange = "visibilitychange";
}
if (hidden! = null && visibilityChange! = null) {
addEvent (dokumen, perubahan visibilitas, fungsi (acara) {
document.getElementById ("x"). innerHTML + = visibilityChange + ":" + hidden + "=" + dokumen [tersembunyi] + "<br>";
});
}
var potentialPageVisibility = {
pageVisibilityChangeThreshold: 3 * 3600, // dalam detik
init: function () {
fungsi setAsNotHidden () {
var dispatchEventRequired = document.potentialHidden;
document.potentialHidden = false;
document.potentialHiddenSince = 0;
if (dispatchEventRequired) dispatchPageVisibilityChangeEvent ();
}
function initPotentialHiddenDetection () {
if (! hasFocusLocal) {
// jendela tidak memiliki fokus => periksa aktivitas pengguna di jendela
lastActionDate = Tanggal baru ();
if (timeoutHandler! = null) {
clearTimeout (timeoutHandler);
}
timeoutHandler = setTimeout (checkPageVisibility, potentialPageVisibility.pageVisibilityChangeThreshold * 1000 + 100); // +100 ms untuk menghindari masalah pembulatan di bawah Firefox
}
}
function dispatchPageVisibilityChangeEvent () {
unifiedVisilityChangeEventDispatchAllowed = false;
var evt = document.createEvent ("Event");
evt.initEvent ("potentialvisilitychange", true, true);
document.dispatchEvent (evt);
}
function checkPageVisibility () {
var potentialHiddenDuration = (hasFocusLocal || lastActionDate == null? 0: Math.floor ((Tanggal baru (). getTime () - lastActionDate.getTime ()) / 1000));
document.potentialHiddenSince = potentialHiddenDuration;
if (potentialHiddenDuration> = potentialPageVisibility.pageVisibilityChangeThreshold &&! document.potentialHidden) {
// ambang perubahan visibilitas halaman raiched => naikkan genap
document.potentialHidden = true;
dispatchPageVisibilityChangeEvent ();
}
}
var lastActionDate = null;
var hasFocusLocal = true;
var hasMouseOver = true;
document.potentialHidden = false;
document.potentialHiddenSince = 0;
var timeoutHandler = null;
addEvent (dokumen, "pageshow", fungsi (acara) {
document.getElementById ("x"). innerHTML + = "pageshow / doc: <br>";
});
addEvent (dokumen, "pagehide", function (event) {
document.getElementById ("x"). innerHTML + = "pagehide / doc: <br>";
});
addEvent (jendela, "pageshow", fungsi (acara) {
document.getElementById ("x"). innerHTML + = "pageshow / win: <br>"; // terangkat saat halaman pertama kali ditampilkan
});
addEvent (window, "pagehide", function (event) {
document.getElementById ("x"). innerHTML + = "pagehide / win: <br>"; // tidak dibangkitkan
});
addEvent (dokumen, "mousemove", fungsi (acara) {
lastActionDate = Tanggal baru ();
});
addEvent (dokumen, "mouseover", fungsi (acara) {
hasMouseOver = true;
setAsNotHidden ();
});
addEvent (dokumen, "mouseout", fungsi (acara) {
hasMouseOver = false;
initPotentialHiddenDetection ();
});
addEvent (window, "blur", function (event) {
hasFocusLocal = false;
initPotentialHiddenDetection ();
});
addEvent (jendela, "fokus", fungsi (acara) {
hasFocusLocal = true;
setAsNotHidden ();
});
setAsNotHidden ();
}
}
potentialPageVisibility.pageVisibilityChangeThreshold = 4; // 4 detik untuk pengujian
potentialPageVisibility.init ();
</script>
Karena saat ini tidak ada solusi lintas-browser yang berfungsi tanpa false positive, Anda sebaiknya berpikir dua kali untuk menonaktifkan aktivitas berkala di situs web Anda.
requestAnimationFrame
API, atau gunakan fitur modern yang frekuensisetTimeout
/setInterval
berkurang ketika jendela tidak terlihat (1 detik di Chrome, misalnya).