廢話不說,直接進正題。
最近項目有個需求需要在用戶關閉頁面時將頁面存留的統計數據發送到後端。該需求有兩個關鍵點:
- 監聽頁面卸載
- 在卸載時發送數據
如何監聽用戶關閉頁面
首先我們需要明確,哪些場景屬於用戶關閉頁面:
- 關閉瀏覽器
- 關閉/刷新頁面
可監聽上述場景的API爲:
- unload
- beforeunload
- pagehide
- visibilitychange
但在許多情況下(尤其是移動設備)瀏覽器不會產生 unload、beforeunload 或 pagehide 事件。下面列出了一種不觸發上述事件的情況:
- 用戶加載了網頁並與其交互。
- 完成瀏覽後,用戶切換到了其它應用程序,而不是關閉選項卡。
- 隨後,用戶通過手機的應用管理器關閉了瀏覽器應用。
故此,我們採用visibilitychange + pagehide的組合方式監聽用戶行爲。
if((typeof document.onvisibilitychange) !== 'undefined') {
document.addEventListener('visibilitychange', function logData() {
if (document.visibilityState === 'hidden') {
// ... 發送數據
}
});
}else if((typeof window.onpagehide) !== 'undefined') {
window.addEventListener("pagehide", event => {
if (event.persisted) {
/* the page isn't being discarded, so it can be reused later */
}
}, false);
}
如何在卸載時發送數據
方法一: window.navigator.sendBeacon
語法
navigator.sendBeacon(url, data);
參數:
-
url:表明 data 將要被髮送到的網絡地址。
-
data(可選): 將要發送的 ArrayBuffer、ArrayBufferView、Blob、DOMString、FormData 或 URLSearchParams 類型的數據。
返回值:當成功將數據加入傳輸隊列返回true
,否則返回false
。
示例
const blob = new Blob([JSON.stringify(data)], { type: 'application/json; charset=UTF-8'});
window.sendBeacon(url, blob);
其他
- 數據限制:在大多瀏覽器上最多隻能發送64kb的數據(親測Chrome及Safari瀏覽器上最多發送64kb)。
- 請求方法:通過POST請求發送數據。
- 請求頭: 通過傳入數據data自動設置請求頭,一般的: FormData: multipart/form-data,DomString: text/plain ,想傳遞json數據到後端,可以通過Blob對象間接達到設置Content-type的效果。
瀏覽器兼容
方法二: fetch設置keepalive爲true
語法
Promise
fetch(input[, init]);
參數詳見:fetch()-MDN
示例
fetch(url, {
body: data,
mode: 'no-cors',
method: 'POST',
headers: { 'Content-Type': 'application/json'}
}).then(response => response.json())
.then(data => console.log(data));
其他
- 數據限制:設置keepalive爲true,最多隻能發送64kb的數據(親測Chrome及Safari瀏覽器上最多發送64kb)。
瀏覽器兼容
參考
- fetch()-MDN
- Navigator.sendBeacon()-MDN
- visibilitychange-MDN
- Window: 頁面隱藏事件 (pagehide event)
- Navigator.sendBeacon() data size limits
- When fetch is used keepalive is the default, and Chrome only allows a POST body <= 65536 bytes in that scenario
- 監聽用戶關閉瀏覽器、離開瀏覽器事件
- 深度好文: 從js visibilitychange Safari下無效說開去
- fetch協議
- Beacon標準