JS監(jiān)聽頁面可見性可通過page visibility api實(shí)現(xiàn),1.使用document.visibilitystate屬性獲取頁面狀態(tài),值為”visible”或”hidden”等;2.監(jiān)聽document上的visibilitychange事件以觸發(fā)相應(yīng)操作;3.結(jié)合requestanimationframe控制動(dòng)畫執(zhí)行;4.使用intersection observer api檢測(cè)元素是否進(jìn)入視口。監(jiān)聽頁面可見性可優(yōu)化資源消耗,如暫停視頻播放、停止數(shù)據(jù)輪詢等,提升性能與用戶體驗(yàn)。對(duì)于兼容性問題,可通過polyfill方案模擬visibilitychange行為。此外,在單頁應(yīng)用中,intersection observer可用于動(dòng)態(tài)監(jiān)測(cè)主要內(nèi)容區(qū)域的可見狀態(tài)。
JS怎樣監(jiān)聽頁面可見性?簡單來說,就是用一些API來感知用戶是不是真的在看你的網(wǎng)頁,而不是切到別的標(biāo)簽頁或者最小化了。這很重要,因?yàn)槟憧梢愿鶕?jù)這個(gè)狀態(tài)來優(yōu)化你的應(yīng)用,比如暫停視頻播放、停止輪詢數(shù)據(jù)等等,節(jié)省資源,提升用戶體驗(yàn)。
解決方案
JS提供了一些原生的API來幫助我們實(shí)現(xiàn)這個(gè)功能,讓我們能精確地知道頁面在用戶眼前的狀態(tài)。
-
document.visibilityState: 這個(gè)屬性告訴你當(dāng)前頁面的可見狀態(tài)。它的值可以是 “visible” (可見), “hidden” (隱藏), “prerender” (預(yù)渲染), 或 “unloaded” (卸載)。這是最常用的一個(gè)屬性,直接告訴你頁面是不是在用戶的視線范圍內(nèi)。
-
visibilitychange 事件: 當(dāng)頁面的可見狀態(tài)改變時(shí),會(huì)觸發(fā)這個(gè)事件。你可以在 document 上監(jiān)聽這個(gè)事件,然后根據(jù) document.visibilityState 的值來執(zhí)行相應(yīng)的操作。這比定時(shí)檢查 document.visibilityState 要高效得多。
-
Page Visibility API: document.hidden 屬性,雖然現(xiàn)在用的不多,但還是有必要了解一下。它是一個(gè)布爾值,告訴你頁面是否隱藏。相當(dāng)于 document.visibilityState === ‘hidden’ 的簡寫。
-
requestAnimationFrame: 雖然它不是直接用來檢測(cè)可見性的,但可以結(jié)合使用。當(dāng)頁面不可見時(shí),瀏覽器會(huì)暫停 requestAnimationFrame 的回調(diào),所以你可以利用這一點(diǎn)來判斷頁面是否可見,從而停止一些動(dòng)畫或渲染操作。
-
Intersection Observer API: 這個(gè)API主要用于檢測(cè)元素是否進(jìn)入視口,但你也可以用它來間接檢測(cè)頁面是否可見。如果你的頁面只有一個(gè)主要內(nèi)容區(qū)域,你可以監(jiān)聽這個(gè)區(qū)域是否進(jìn)入視口,從而判斷頁面是否可見。
為什么需要監(jiān)聽頁面可見性?頁面隱藏時(shí)暫停不必要的資源消耗
監(jiān)聽頁面可見性,最直接的好處就是優(yōu)化性能。想象一下,如果用戶切換到其他標(biāo)簽頁,你的網(wǎng)頁還在不停地發(fā)送請(qǐng)求、播放視頻、執(zhí)行動(dòng)畫,那簡直就是在浪費(fèi)用戶的電量和流量。通過監(jiān)聽 visibilitychange 事件,你可以在頁面隱藏時(shí)暫停這些操作,等到頁面重新可見時(shí)再恢復(fù)。這對(duì)于移動(dòng)設(shè)備尤其重要,可以顯著延長電池續(xù)航。
visibilitychange 事件的兼容性問題及polyfill方案
雖然 visibilitychange 事件已經(jīng)得到了廣泛的支持,但在一些老版本的瀏覽器中可能仍然存在兼容性問題。為了解決這個(gè)問題,你可以使用一些 polyfill 方案。這些 polyfill 通常會(huì)通過定時(shí)檢查 document.hidden 屬性來模擬 visibilitychange 事件的行為。當(dāng)然,使用 polyfill 會(huì)帶來一些額外的性能開銷,所以在選擇時(shí)需要權(quán)衡利弊。一個(gè)簡單的polyfill方案可以這樣實(shí)現(xiàn):
if (typeof document.hidden !== "undefined") { // Use the standard property and event var hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState"; } else if (typeof document.msHidden !== "undefined") { hidden = "msHidden"; visibilityChange = "msvisibilitychange"; visibilityState = "msVisibilityState"; } else if (typeof document.webkitHidden !== "undefined") { hidden = "webkitHidden"; visibilityChange = "webkitvisibilitychange"; visibilityState = "webkitVisibilityState"; } document.addEventListener(visibilityChange, function() { if (document[hidden]) { // 頁面隱藏時(shí)執(zhí)行的操作 console.log("頁面隱藏"); } else { // 頁面可見時(shí)執(zhí)行的操作 console.log("頁面可見"); } }, false);
如何利用 requestAnimationFrame 優(yōu)化動(dòng)畫效果?
requestAnimationFrame 的一個(gè)重要特性是,當(dāng)頁面不可見時(shí),瀏覽器會(huì)自動(dòng)暫停其回調(diào)函數(shù)的執(zhí)行。這意味著你可以利用 requestAnimationFrame 來優(yōu)化動(dòng)畫效果,避免在頁面隱藏時(shí)浪費(fèi)資源。例如,你可以將動(dòng)畫邏輯放在 requestAnimationFrame 的回調(diào)函數(shù)中,并在頁面可見時(shí)啟動(dòng)動(dòng)畫,頁面隱藏時(shí)停止動(dòng)畫。這樣可以確保動(dòng)畫只在用戶真正看到的時(shí)候才執(zhí)行,從而提高性能和用戶體驗(yàn)。
let animationFrameId; function animate() { // 動(dòng)畫邏輯 console.log("執(zhí)行動(dòng)畫"); animationFrameId = requestAnimationFrame(animate); } document.addEventListener("visibilitychange", function() { if (document.hidden) { // 頁面隱藏時(shí)停止動(dòng)畫 cancelAnimationFrame(animationFrameId); } else { // 頁面可見時(shí)啟動(dòng)動(dòng)畫 animationFrameId = requestAnimationFrame(animate); } }); // 初始啟動(dòng)動(dòng)畫 animationFrameId = requestAnimationFrame(animate);
Intersection Observer API 在單頁應(yīng)用中的應(yīng)用場(chǎng)景
在單頁應(yīng)用(SPA)中,頁面內(nèi)容通常是動(dòng)態(tài)加載的,這意味著你可能需要更靈活的方式來檢測(cè)頁面是否可見。Intersection Observer API 可以幫助你實(shí)現(xiàn)這一點(diǎn)。你可以監(jiān)聽頁面主要內(nèi)容區(qū)域的可見性,從而判斷頁面是否在用戶的視線范圍內(nèi)。例如,你可以創(chuàng)建一個(gè) IntersectionObserver 實(shí)例,監(jiān)聽根元素為 document.documentElement,然后觀察頁面中的主要內(nèi)容區(qū)域。當(dāng)內(nèi)容區(qū)域進(jìn)入視口時(shí),你可以認(rèn)為頁面是可見的,反之則認(rèn)為頁面是隱藏的。這種方式比直接監(jiān)聽 visibilitychange 事件更加靈活,可以適應(yīng)各種復(fù)雜的頁面結(jié)構(gòu)。