1. 程式人生 > >Page Visibility(頁面可見性) API介紹、微拓展

Page Visibility(頁面可見性) API介紹、微拓展

這篇文章釋出於 2012年11月29日,星期四,23:30,歸類於 web綜合。 閱讀 66103 次, 今日 2 次

一、網頁君的悲情誰來懂

唉,突然想到了一首悲情詩:

淚溼羅巾夢不成,夜深前殿按歌聲。
紅顏未老恩先斷, 斜倚薰籠坐到明。

學生時代學過的一首詩,已還給老師不知所云的諸位可參見下面釋義:

詩的主人公是一位不幸的宮女。她一心盼望君王的臨幸而終未盼得,時已深夜,只好上床,已是一層怨悵。寵幸不可得,退而求之好夢;輾轉反側,竟連夢也難成,見出兩層怨悵。夢既不成,索性攬衣推枕,掙扎坐起。正當她愁苦難忍,淚溼羅巾之時,前殿又傳來陣陣笙歌,原來君王正在那邊尋歡作樂,這就有了三層怨悵。倘使人老珠黃,猶可解說;偏偏她盛鬢堆鴉,紅顏未老,生出四層怨悵。要是君王一直沒有發現她,那也罷了;事實是她曾受過君王的恩寵,而現在這種恩寵卻無端斷絕,見出五層怨悵。夜已深沉,瀕於絕望,但一轉念,猶翼君王在聽歌賞舞之後,會記起她來。於是,斜倚熏籠,濃薰翠袖,以待召幸。不料,一直坐到天明,幻想終歸破滅,見出六層怨悵。

為何在這陽光和煦,安靜愜意的溫暖冬日會有如此感傷呢?

唉,只因自己想到了可憐的網頁君,其命運就跟深宮的宮女一般,令人唏噓。

某君王啪啪啪啪打開了十幾二十個選項卡(就像他當初啪啪啪啪寵幸後宮那十幾二十個宮女一樣);但是,鞭長莫及,其一次只能瀏覽一個選項卡(就像他每晚只能寵幸一個宮女一樣);可是,其他的選項卡並不知道君王何時會再過來(就像其他的宮女並不清楚君王今晚會不會來寵幸一樣);於是,其他選項卡依然在不停地執行,守候(就像宮女依然留有希望,等待召幸);然而,最後,君王直接啪一下瀏覽器關掉了,N多不停忠心守候的選項卡被無情漠視了(就像宮女們苦守整夜,結果卻是一場空,只能以淚洗面)!

此番悲情怎能不讓人同情憐憫,是不是啊,諸位!

哼,請不要擺出這樣或這樣的表情。
那個誰誰,說的就是你!你應該這樣子或這樣子

您應該像扎西拉姆·多多一樣,為悲情網頁君賦詩一首——《見與不見》:

你見,或者不見我
我就在那裡
不悲不喜
你念,或者不念我
情就在那裡
不來不去……

時代在發展,制度也會進步。比方說明代吧,每日天漸黑時,嬪妃所住的宮門前,都掛起兩隻紅紗籠燈。皇帝臨幸某宮,則該宮門上的燈卸下來,表示皇帝已選定寢宿的地方。於是,負責巡街的宦官,傳令其他各宮均卸燈寢息。失意的嬪妃們只得滅掉希求寵幸的紅紗籠,明晚再重新掛上。

這就避免了嬪妃們徹夜苦等,哀怨淚雨的情形。

那網頁君這邊呢?

好在,就最近幾年,網頁君也有了相應的東西,可以告知網頁你是“寵幸”了呢還是不被“寵幸”,這樣,可以讓網頁君在不被“寵幸”時候安心睡覺,或者養個小白。這個東西就是Page Visibility API,翻譯成簡體中文就是“頁面可見性應用程式介面”。

於是乎,網頁君的悲情程度可以lower一點了,從這點來說,Page Visibility API是個很人性化的設計,感動

//zxx: 為接地氣,下”Page Visibility API”均稱呼為“頁面可見性API”。

二、頁面可見性API究竟為何物?

CSS中有個有用且有趣且個人比較喜歡的屬性 – visibility. 其有兩個常用屬性值:hiddenvisible. 分別表示不可見與可見。OK,本文所說的API中也有Visibility這個單詞,那他們表意一致?

回答是:YES! //眾人:妹啊,你以為是中國達人秀啊!

頁面可見性API就是表示網頁可見還是不可見的,巧的是,hiddenvisible就是該API的兩個狀態值。

舉個通俗的例子:
如果你在xxxxx.com上瀏覽提神的圖片,則當前你所看的這個網頁的visibility就是visible.

此時,如果你老媽子突然進來給你送香蕉,出現下圖所示場景:
總是在看桌面

則,此時之前提神的網頁的visibility就是hidden – 最小化。

或者老媽子進來的時候,切換到人民網,提神網頁的visibility也是hidden – 切換選項卡。

老媽子送的香蕉~~啦啦啦啦啦~~

這就是頁面可見性API的直觀認識,至於其身上哪裡有麻子,下面會指出.

三、頁面可見性API屬性和事件

目前頁面可見性API有兩個屬性,一個事件,如下:

  • document.hidden: Boolean值,表示當前頁面可見還是不可見
  • document.visibilityState: 返回當前頁面的可見狀態。
    1. hidden
    2. visible
    3. prerender” 這個表示納尼呢~~恩,我也不確定,字面意思是“預渲染”。莫非指的是啪啪啪一下子開了很多個選項卡,之前選項卡依然在載入渲染的狀態?或者說是瀏覽器新開啟時記住的上一次關閉選項卡的狀態?求達人指明!
    4. preview” 預覽。根據部分2011年底相關國外部分文章的說法,這種狀態出現在,如window7系統下,滑鼠放在底部(一般是)工作列的圖示上(預覽)的時候。見下截圖:
      win7滑鼠圖示程式介面預覽 張鑫旭-鑫空間-鑫生活

      但是根據自己的實際測試,似乎並沒有這種狀態的改變——包括IE10瀏覽器。可能是時代改變,一切都遵循規範了吧。因此,我們重點關注前面三個狀態值就可以了。

  • visibilitychange: 當可見狀態改變時候觸發的事件。

四、瀏覽器支援與私有字首

我寫了個如下的頁面可見性API支援性的測試程式碼:

var isPageVisibilitySupport = (function() {
    var support = false;
    if (typeof window.screenX === "number") {
        ["webkit", "moz", "ms", "o", ""].forEach(function(prefix) {
            if (support == false && document[prefix + (prefix? "H": "h") + "idden"] + "" !== "undefined") {
                support = true;
            }
        });        
    }
    return support;
})();

測試發現,如下瀏覽器都是支援的

  • Chrome 21
  • FireFox 16.0.2
  • Opera 12.11
  • IE10

不支援的瀏覽器:

  • IE9
  • Safari 5.1

因此,typeof document.msHidden != "undefined"可以用來區分IE9瀏覽器還是IE10瀏覽器。

正如上面的code所展示的,頁面可見性API的所有屬性以及事件,目前是需要使用私有字首的(如果沒有這些字首,瀏覽器就不認識這些屬性或方法了)。
一旦有了字首,實際應用的時候程式碼就有些囉哩吧嗦了(可見參見文章底部參考文章中展示的程式碼)!

因為要一個字首一個字首判斷——oh, my! 我這個懶人最不喜歡這等麻煩事了,於是,撈起袖子,啪啪啪啪整個一個相容性的Page Visibility API相關物件,正好包含API中的兩個屬性以及一個事件。完整程式碼如下(節省篇幅,滾動顯示
):

var pageVisibility = (function() {
    var prefixSupport, keyWithPrefix = function(prefix, key) {
        if (prefix !== "") {
            // 首字母大寫
            return prefix + key.slice(0,1).toUpperCase() + key.slice(1);    
        }
        return key;
    };
    var isPageVisibilitySupport = (function() {
        var support = false;
        if (typeof window.screenX === "number") {
            ["webkit", "moz", "ms", "o", ""].forEach(function(prefix) {
                if (support == false && document[keyWithPrefix(prefix, "hidden")] != undefined) {
                    prefixSupport = prefix;
                    support = true;   
                }
            });        
        }
        return support;
    })();

    var isHidden = function() {
        if (isPageVisibilitySupport) {
            return document[keyWithPrefix(prefixSupport, "hidden")];
        }
        return undefined;
    };

    var visibilityState = function() {
        if (isPageVisibilitySupport) {
            return document[keyWithPrefix(prefixSupport, "visibilityState")];
        }
        return undefined;
    };

    return {
        hidden: isHidden(),
        visibilityState: visibilityState(),
        visibilitychange: function(fn, usecapture) {
            usecapture = undefined || false;
            if (isPageVisibilitySupport && typeof fn === "function") {
                return document.addEventListener(prefixSupport + "visibilitychange", function(evt) {
                    this.hidden = isHidden();
                    this.visibilityState = visibilityState();
                    fn.call(this, evt);
                }.bind(this), usecapture);
            }
            return undefined;
        }
    };    
})(undefined);

或者直接呼叫:

<script src="http://www.zhangxinxu.com/study/201211/pageVisibility.js"></script>

其中具體細節無需關心,實際上上面這麼多程式碼本質上就是下面這點:

var pageVisibility = {
    hidden: Boolean
    visibilityState: String
    visibilitychange: Function
};

與_原生屬性事件_對應關係如下:

pageVisibility.hidden === document.hidden(相容處理)
pageVisibility.visibilityState=== document.visibilityState(相容處理)
pageVisibility.visibilitychange(function() { /* this指的就是pageVisibility */ }); === document.addEventListener("visibilitychange", function() {});(相容處理)

於是,要判斷一個瀏覽器是否支援頁面可見性API如下程式碼就可以了(無需什麼webkit或moz或ms等字首一個個判斷了):

var isSupport = typeof pageVisibility.hidden !== "undefined"

網頁可見性 API基本屬性與事件例項頁面截圖 張鑫旭-鑫空間-鑫生活

對於不支援的瀏覽器,如IE9瀏覽器,顯示的則是”undefined“:
不支援網頁可見性API瀏覽器顯示undefined  張鑫旭-鑫空間-鑫生活

OK,萬屎具備,只欠草紙了!下面,看看,頁面可見性API都有些可以有的實際應用。

//zxx: 下面為廣告~~注意不要勿點~~嘻嘻~~

五、頁面可見性API實際應用

先來看看老外給的一個例子,我覺得很有實際應用價值的。

進去後,會有一個HTML5 video顯示的Google Chrome瀏覽器廣告的30秒funny視訊,如下圖所示:
視訊截圖

直接瀏覽你是看不出什麼玄乎的,請切換一個選項卡,讓該頁面置於後面,結果,您會發現這個選項卡的標題欄變成了這樣:
標題欄顯示視訊暫停以及暫停時間

看出來沒?視訊播放被中斷了——當page不可見的時候,視訊會自動暫停!

此時,您再進入該選項卡,視訊又從剛才的地方繼續播放了,如下截圖:
頁面可見視訊繼續播放 張鑫旭-鑫空間-鑫生活

個人愚見,國內的一些視訊站點是不是可以應用下這個API呢!這樣當媽媽進來送香蕉的時候,直接win+D顯示桌面就可以了,聲音啊什麼的會自動關掉,振奮視訊自動暫停,多讚的一個功能啊!以前的暫停視訊+最小化瀏覽器直接變成了一步→最小化,節約了大量的寶貴時間,極大了提升了使用者體驗,恩!不錯!!

上面的例子畢竟長在外人田啊,一旦建起了圍牆就看不到了,因此,自己折騰了一個簡單的10秒鐘低質量的貓貓版本。//zxx: 上面例子視訊3M+,我估算了下,1000次訪問的話,我勒個去,差不多3個G的流量去了,我現在每月流量都岌岌可危,因此,大家將就下下這個百來K的視訊(Chrome瀏覽器以及IE10下可訪問,或者誰給我尺寸小一點的ogv格式任意視訊,讓FireFox也能OK)~~

操作同上,進入頁面播放,離開頁面暫停。
Chrome瀏覽器下效果截圖 張鑫旭-鑫空間-鑫生活

登入同步
這是我想的一個覺得蠻實用的應用。有如下場景:
1. 去淘寶買東西,未登入狀態下,進入首頁。
2. 然後新視窗開啟任意頁面,登入併成功返回。
淘寶網成功登入 張鑫旭-鑫空間-鑫生活
3. 再次訪問剛才開啟的首頁,發現頁面還是未登入狀態(見下圖),實際上使用者已經登入了。
之前的首頁仍然是未登入狀態

目前,這種狀態大家似乎習以為常,覺得很OK,實際上這種糟糕的。就像沒有空調的歲月裡,人們覺得風扇很OK啊;但是,現在呢,還有誰屋頂吊個風扇嗎!!有了頁面可見性API,我們可以把體驗做地更好。

不出意外,您預設進來應該是提示你登入的:

點選上圖所示的“登入”文字連結,會在新視窗無重新整理登入。任意使用者名稱和密碼,成功後再回到之前提示的登入頁面,已經變成了:“歡迎回來,某某某”了!

只要該頁面不被關閉,你怎樣重新整理,都是“歡迎回來,某某某”。不過,在實際應用中,檢測到已經登入成功,直接重新整理當前頁面的居多!IE10下,貌似本地儲存無法同源不同頁面共享,這使得通過HTML5本地儲存共享資訊的做法遇到了些許阻礙。

精確的線上時長
這個不用多說,只有使用者當前這個頁面可見的時候,才計算線上時間,這樣可以避免掛機的情況,時長計算更準確(這個可能不是個好idea)。

線上聊天離開狀態
網頁聊天的時候,可以知道使用者是否“離開”還是“離線”還是“下線”。當前頁面不可見,但連線還在的時候,我們可以確定該人是離開的(涉及隱私,可能也不是個好idea)。

以及其他些應用需求
等到了實際需求的時候,就會想到頁面可見性API,看看能不能漸進增加下使用者體驗等。

六、結語

腦細胞不夠用了,肯定還有很多現有的可以應用在實際專案中的idea的,一時想不出——恩,比方說,每次使用者切換到你這個頁面上的時候,logo抖一下,或頁面一道亮光閃過,後者歡迎語之類……總之,是個很有用很有趣的API.

此API支援日趨穩定,不會有被去除的可能,因此,大夥兒可以放心大膽嘗試之……因為是新東西,您的任何小小idea都會是首創,領先的創造者——開動你的腦筋,發揮你的創造性思維,讓我們的網頁更加生動多彩吧

集思廣益,歡迎補充!如有錯誤,歡迎糾正!

參考文章:


(本篇完)