檢測用戶在線狀態的核心方法是使用 navigator.online 屬性和 online/offline 事件,1. 初始加載時通過 navigator.online 檢測網絡狀態;2. 使用 online 和 offline 事件監聽網絡變化;3. 結合心跳檢測提升準確性,防止誤判;4. 使用防抖或延遲提示避免頻繁切換帶來的不良體驗;5. 在 react 或 vue 等框架中可通過生命周期或 hook 集成上述邏輯;6. 可選使用 network information api 獲取更詳細網絡信息,但兼容性有限。
檢測用戶是否在線,實際上就是在前端監測用戶的網絡連接狀態。這事兒挺重要的,尤其是在WebApp里,用戶體驗直接受影響。
解決方案
核心思路就是利用瀏覽器提供的 navigator.onLine 屬性和 online/offline 事件。navigator.onLine 告訴你當前瀏覽器是否認為自己在線,online 和 offline 事件分別在網絡狀態改變時觸發。
-
初始狀態檢測:
頁面加載時,先檢查一次 navigator.onLine,根據返回值顯示不同的提示信息。
if (navigator.onLine) { console.log("用戶在線"); // 可以加載在線內容 } else { console.log("用戶離線"); // 顯示離線提示 }
-
監聽 online 和 offline 事件:
這兩個事件分別在網絡連接恢復和斷開時觸發。
window.addEventListener('online', function(e) { console.log("網絡已連接"); // 重新加載數據,或者顯示在線提示 }); window.addEventListener('offline', function(e) { console.log("網絡已斷開"); // 顯示離線提示,保存未發送的數據 });
-
更完善的方案:心跳檢測
navigator.onLine 有時候不太靠譜,比如用戶連接了WiFi但無法訪問外網,它仍然會返回 true。所以,可以結合心跳檢測。
定期向服務器發送請求,如果請求失敗,就認為用戶離線。
function heartbeat() { fetch('/api/heartbeat') // 假設服務器有一個心跳接口 .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } // console.log("心跳檢測成功"); }) .catch(error => { console.log("心跳檢測失敗,用戶可能離線", error); // 處理離線邏輯 }) .finally(() => { setTimeout(heartbeat, 5000); // 每5秒檢測一次 }); } heartbeat();
服務器端的心跳接口,只需要簡單地返回一個 200 OK 即可。
如何處理網絡不穩定情況,避免頻繁切換在線/離線狀態?
這個問題挺實際的。如果網絡不穩定,online 和 offline 事件會頻繁觸發,導致用戶體驗很差。
-
防抖 (Debounce):
使用防抖函數,只有在一段時間內網絡狀態沒有變化時,才執行相應的操作。
function debounce(func, delay) { let timeout; return function(...args) { const context = this; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), delay); }; } const handleOnline = debounce(() => { console.log("網絡已連接 (防抖)"); // 重新加載數據 }, 1000); // 1秒延遲 const handleOffline = debounce(() => { console.log("網絡已斷開 (防抖)"); // 顯示離線提示 }, 1000); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline);
-
延遲提示:
不要立即顯示離線提示,而是等待一段時間,如果網絡仍然斷開,再顯示提示。
let offlineTimeout; window.addEventListener('offline', function(e) { offlineTimeout = setTimeout(() => { console.log("網絡已斷開 (延遲提示)"); // 顯示離線提示 }, 3000); // 3秒延遲 }); window.addEventListener('online', function(e) { clearTimeout(offlineTimeout); // 清除延遲提示 console.log("網絡已連接 (延遲提示)"); // 重新加載數據 });
如何在React或vue等框架中使用這些技術?
其實思路是一樣的,只是需要在框架的生命周期函數或者hooks里使用。
React:
import React, { useState, useEffect } from 'react'; function NetworkStatus() { const [isOnline, setIsOnline] = useState(navigator.onLine); useEffect(() => { const handleOnline = () => setIsOnline(true); const handleOffline = () => setIsOnline(false); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return ( <div> {isOnline ? '在線' : '離線'} </div> ); } export default NetworkStatus;
Vue (Composition API):
<template> <div> {{ isOnline ? '在線' : '離線' }} </div> </template> <script> import { ref, onMounted, onUnmounted } from 'vue'; export default { setup() { const isOnline = ref(navigator.onLine); const handleOnline = () => isOnline.value = true; const handleOffline = () => isOnline.value = false; onMounted(() => { window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); }); onUnmounted(() => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }); return { isOnline }; } } </script>
心跳檢測也類似,只是需要在 useEffect 或 onMounted 里啟動定時器。
除了 navigator.onLine 和 online/offline 事件,還有其他更高級的API可以用來檢測網絡狀態嗎?
有,但兼容性可能不太好,而且實際使用場景不多。
-
Network Information API:
這個API提供了更詳細的網絡信息,比如連接類型(WiFi, 4G, etc.)和預估的帶寬。
if ('connection' in navigator) { const connection = navigator.connection; console.log("連接類型:", connection.effectiveType); console.log("下行速度:", connection.downlink); }
但這個API的兼容性不是很好,而且很多瀏覽器已經廢棄了一些屬性。
-
Service Worker 的 background Sync API:
這個API可以在網絡恢復時自動同步數據。雖然不是直接用來檢測網絡狀態,但可以用來處理離線場景。
總的來說,navigator.onLine 和 online/offline 事件已經足夠滿足大部分需求。結合心跳檢測和防抖/延遲提示,可以提供比較好的用戶體驗。