妙趣橫生的HTML5 Page Visibility API
起因
最近瀏覽36kr 的網頁的時候偶然發現一個有趣的情況:當瀏覽器Tab 處於非當前頁的時候,36kr 的標題欄會自動換成可愛的大白字元形象。Jeff 在第一次看到的時候就知道這種效果是通過HTML5 的Page Visibility API
實現的(不是吹牛)。
直到現在我還沒去檢視36kr 的原始碼看其是如何實現的(也不打算去一個個檢視它繁雜的js 檔案了),HTML5 的Page Visibility API
以前看過,看到36kr 實現了這個的時候一時興起,遂去檢視文件深入瞭解之。然後三兩下在自己的部落格上實現了類似的效果(你可以切換Tab 到背後看看):
深入解析Page Visibility API
自從騰訊面試二面後,深深意識到“不去刨根問底的工程師跟搬磚的沒啥區別”;雖然我一直認為好的技術文不應該過多複製API 文件的內容,但在這裡還是從自己的角度為沒接觸過這個Page Visibility API
的同志們解析下。
荒蕪年代一統天下的IE6 早已成為過去時(也許你還記得以前用IE6的時候每開啟一個頁面就彈出一個新的視窗,層層疊疊),現代瀏覽器在多Tab (標籤後窗口)的構建形式上基本達成了共識,通常而言我們都是開啟新標籤頁,在當前瀏覽器視窗中,每次都只有一個標籤頁處於啟用態(或者說高亮),其餘均為隱藏態。HTML5 的那幫搞標準的也適時提出了這個Page Visibility API
在這裡我們先稍微離題下,可能你知道,Chrome 瀏覽器較一般瀏覽器能更好穩定執行的原因在於其引入了沙盒機制,每個新建的標籤頁甚至是每個擴充套件都是獨立在一個沙盒執行的。但如此一來帶來的是系統資源的佔用(Chrome 因耗記憶體被詬病就是如此來源於此)。回到正文,瀏覽器中每個標籤頁無論是啟用態還是隱藏態,運作機制模式基本沒啥區別的,原來該計算的還是在計算,原來在放視訊的還是在放視訊,佔記憶體的還是在佔記憶體。
但引入了Page Visibility API
,開發者可以做一些事情,讓我們設想下面的場景並提供相應的demo:
場景一:視訊網站使用者在看視訊時候切換到另外一個標籤頁了,視訊自動暫停(
場景二:一些耗效能的頁面在標籤頁處於隱藏狀態時候自動停止相關運算,節省資源(點選檢視Demo,援引自alloyteam);
場景三:好玩的,比如類似36kr 或本站的效果(點選檢視Demo)。
場景N:桌面提醒Notification 開啟隱藏態免打擾模式、流式載入的新聞頁面在處於隱藏態時偷偷載入最新內容……
基本上,有了這個API,制約你的就是你的idea,你的想象力了。
Page Visibility API使用方法
Page Visibility API
有兩個相關的屬性:document.visibilityState
及document.hidden
。
document.visibilityState
有如下四個值:
hidden
:當瀏覽器最小化、切換tab(the page is on a background tab)、電腦鎖屏時visibilityState值是hidden
visible
:當瀏覽器頂級context(top level browsing context)的document至少顯示在一個螢幕(screen)當中時,返visible;當瀏覽器視窗沒有最小化,但是瀏覽器被其他應用遮擋時,visibilityState值也是visible
prerender
:文件載入離屏(is loaded off-screen)或者不可見時返回prerender,瀏覽器可選擇性的支援這個屬性(not all browsers will necessarily support it)
unloaded
:當文件(document)將要被unload時返回unloaded,瀏覽器可選擇性的支援這個屬性
document.hidden
是個布林值屬性,標籤頁處於隱藏態則為false,反之啟用態為true。
最核心的是通過繫結visibilitychange
事件來達到需求:
document.addEventListener(‘visibilitychange‘,function(event) {
if (!document.hidden) {
// The page is visible.
} else {
// The page is hidden.
}
});
因為相容性的原因需要為相關函式新增不同的瀏覽器字首:
// Get Browser-Specifc Prefixfunction getBrowserPrefix() {
// Check for the unprefixed property. if (‘hidden‘ in document) {
return null;
}
// All the possible prefixes. var browserPrefixes = [‘moz‘,‘ms‘,‘o‘,‘webkit‘];
for (var i = 0; i < browserPrefixes.length; i++) {
var prefix = browserPrefixes[i] + ‘Hidden‘;
if (prefix in document) {
return browserPrefixes[i];
} }
// The API is not supported in browser. return null;
}
// Get Browser Specific Hidden Propertyfunction hiddenProperty(prefix) {
if (prefix) {
return prefix + ‘Hidden‘;
} else {
return ‘hidden‘;
}}
// Get Browser Specific Visibility Statefunction visibilityState(prefix) {
if (prefix) {
return prefix + ‘VisibilityState‘;
} else {
return ‘visibilityState‘;
}}
// Get Browser Specific Eventfunction visibilityEvent(prefix) {
if (prefix) {
return prefix + ‘visibilitychange‘;
} else {
return ‘visibilitychange‘;
}}
更多使用方法請檢視上面的Demo 中的原始碼。
部分參考來源:
https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Usi...
http://www.alloyteam.com/2012/11/page-visibility-api/
http://code.tutsplus.com/articles/html5-page-visibility-api–cms-22021