監聽用戶關閉瀏覽器、離開瀏覽器事件

做者: 阮一峯javascript

www.ruanyifeng.com/blog/2018/10/page_visibility_api.htmlhtml

1、簡介

有時候,開發者須要知道,用戶正在離開頁面。經常使用的方法是監聽下面三個事件。java

  • pagehide
  • beforeunload
  • unload

可是,這些事件在手機上可能不會觸發,頁面就直接關閉了。由於手機系統能夠將一個進程直接轉入後臺,而後殺死。api

  • 用戶點擊了一條系統通知,切換到另外一個 App。
  • 用戶進入任務切換窗口,切換到另外一個 App。
  • 用戶點擊了 Home 按鈕,切換回主屏幕。
  • 操做系統自動切換到另外一個 App(好比,收到一個電話)。

上面這些狀況,都會致使手機將瀏覽器進程切換到後臺,而後爲了節省資源,可能就會殺死瀏覽器進程。瀏覽器

之前,頁面被系統切換,以及系統清除瀏覽器進程,是沒法監聽到的。開發者想要指定,任何一種頁面卸載狀況下都會執行的代碼,也是沒法作到的。爲了解決這個問題,就誕生了 Page Visibility API。無論手機或桌面電腦,全部狀況下,這個 API 都會監聽到頁面的可見性發生變化。緩存

這個新的 API 的意義在於,經過監聽網頁的可見性,能夠預判網頁的卸載,還能夠用來節省資源,減緩電能的消耗。好比,一旦用戶不看網頁,下面這些網頁行爲都是能夠暫停的。服務器

  • 對服務器的輪詢
  • 網頁動畫
  • 正在播放的音頻或視頻

2、document.visibilityState

這個 API 主要在document對象上,新增了一個document.visibilityState屬性。該屬性返回一個字符串,表示頁面當前的可見性狀態,共有三個可能的值。ide

  • hidden:頁面完全不可見。
  • visible:頁面至少一部分可見。
  • prerender:頁面即將或正在渲染,處於不可見狀態。

其中,hidden狀態和visible狀態是全部瀏覽器都必須支持的。prerender狀態只在支持"預渲染"的瀏覽器上纔會出現,好比 Chrome 瀏覽器就有預渲染功能,能夠在用戶不可見的狀態下,預先把頁面渲染出來,等到用戶要瀏覽的時候,直接展現渲染好的網頁。函數

只要頁面可見,哪怕只露出一個角,document.visibilityState屬性就返回visible。只有如下四種狀況,纔會返回hidden動畫

  • 瀏覽器最小化。
  • 瀏覽器沒有最小化,可是當前頁面切換成了背景頁。
  • 瀏覽器將要卸載(unload)頁面。
  • 操做系統觸發鎖屏屏幕。

能夠看到,上面四種場景涵蓋了頁面可能被卸載的全部狀況。也就是說,頁面卸載以前,document.visibilityState屬性必定會變成hidden。事實上,這也是設計這個 API 的主要目的。

另外,早期版本的 API,這個屬性還有第四個值unloaded,表示頁面即將卸載,如今已經被廢棄了。

注意,document.visibilityState屬性只針對頂層窗口,內嵌的<iframe>頁面的document.visibilityState屬性由頂層窗口決定。使用 CSS 屬性隱藏<iframe>頁面(好比display: none;),並不會影響內嵌頁面的可見性。

3、document.hidden

因爲歷史緣由,這個 API 還定義了document.hidden屬性。該屬性只讀,返回一個布爾值,表示當前頁面是否可見。

document.visibilityState屬性返回visible時,document.hidden屬性返回false;其餘狀況下,都返回true

該屬性只是出於歷史緣由而保留的,只要有可能,都應該使用document.visibilityState屬性,而不是使用這個屬性。

4、visibilitychange 事件

只要document.visibilityState屬性發生變化,就會觸發visibilitychange事件。所以,能夠經過監聽這個事件(經過document.addEventListener()方法或document.onvisibilitychange屬性),跟蹤頁面可見性的變化。

document.addEventListener('visibilitychange', function () {  // 用戶離開了當前頁面 if (document.visibilityState === 'hidden') { document.title = '頁面不可見'; }  // 用戶打開或回到頁面 if (document.visibilityState === 'visible') { document.title = '頁面可見'; } }); 

上面代碼是 Page Visibility API 的最基本用法,能夠監聽可見性變化。

下面是另外一個例子,一旦頁面不可見,就暫停視頻播放。

var vidElem = document.getElementById('video-demo'); document.addEventListener('visibilitychange', startStopVideo); function startStopVideo() { if (document.visibilityState === 'hidden') { vidElem.pause(); } else if (document.visibilityState === 'visible') { vidElem.play(); } } 

5、頁面卸載

下面專門討論一下,如何正確監聽頁面卸載。

頁面卸載能夠分紅三種狀況。

  • 頁面可見時,用戶關閉 Tab 頁或瀏覽器窗口。
  • 頁面可見時,用戶在當前窗口前往另外一個頁面。
  • 頁面不可見時,用戶或系統關閉瀏覽器窗口。

這三種狀況,都會觸發visibilitychange事件。前兩種狀況,該事件在用戶離開頁面時觸發;最後一種狀況,該事件在頁面從可見狀態變爲不可見狀態時觸發。

因而可知,visibilitychange事件比pagehidebeforeunloadunload事件更可靠,全部狀況下都會觸發(從visible變爲hidden)。所以,能夠只監聽這個事件,運行頁面卸載時須要運行的代碼,不用監聽後面那三個事件。

甚至能夠這樣說,unload事件在任何狀況下都沒必要監聽,beforeunload事件只有一種適用場景,就是用戶修改了表單,沒有提交就離開當前頁面。另外一方面,指定了這兩個事件的監聽函數,瀏覽器就不會緩存當前頁面。