偵測網路狀態:Network Information API 與 onLine
在行動優先的時代,網路連線的不穩定是常態。為了提供更好的使用者體驗(例如:在斷線時暫存資料、在弱網環境下載低解析度圖片),我們需要能夠即時偵測使用者的網路狀態。
本篇將整合標準的 navigator.onLine 與進階的 Network Information API,打造一個全方位的網路狀態監測 Composable。
一、 核心 API 介紹
1.1 navigator.onLine
這是所有瀏覽器都支援的基礎 API,只提供一個布林值:
true: 瀏覽器已連接到網路(或區域網路)。false: 瀏覽器已離線。
WARNING
限制:true 只代表電腦有連接到路由器或區域網路,不代表一定能連上網際網路。
1.2 Network Information API
這是一個實驗性 API(目前主要支援 Chromium 核心),提供更詳細的連線資訊,掛載於 navigator.connection:
- effectiveType: 有效連線類型 (
'4g','3g','2g','slow-2g')。 - downlink: 估計下行速度 (Mbps)。
- rtt: 往返延遲時間 (ms)。
- saveData: 使用者是否開啟「節省流量」模式。
二、 封裝 useNetwork Composable
我們將這兩個 API 結合,提供一個完整的網路狀態監測工具。
2.1 介面定義
typescript
export type NetworkType = 'bluetooth' | 'cellular' | 'ethernet' | 'none' | 'wifi' | 'wimax' | 'other' | 'unknown';
export type NetworkEffectiveType = 'slow-2g' | '2g' | '3g' | '4g';
export interface NetworkState {
isOnline: boolean;
offlineAt: number | null;
downlink?: number;
downlinkMax?: number;
effectiveType?: NetworkEffectiveType;
rtt?: number;
saveData?: boolean;
type?: NetworkType;
}2.2 完整實作
typescript
// composables/useNetwork.ts
import { ref, reactive, onMounted, onUnmounted } from 'vue';
export function useNetwork() {
const isSupported = typeof navigator !== 'undefined' && 'connection' in navigator;
const state = reactive<NetworkState>({
isOnline: typeof navigator !== 'undefined' ? navigator.onLine : true,
offlineAt: null,
// 以下屬性僅 Chromium 支援,預設為 undefined
downlink: undefined,
effectiveType: undefined,
rtt: undefined,
saveData: undefined,
type: undefined
});
const updateNetworkInformation = () => {
if (!isSupported) return;
const connection = (navigator as any).connection;
state.downlink = connection.downlink;
state.effectiveType = connection.effectiveType;
state.rtt = connection.rtt;
state.saveData = connection.saveData;
state.type = connection.type;
};
const onOnline = () => {
state.isOnline = true;
state.offlineAt = null;
};
const onOffline = () => {
state.isOnline = false;
state.offlineAt = Date.now();
};
const onConnectionChange = () => {
updateNetworkInformation();
};
onMounted(() => {
if (typeof window === 'undefined') return;
window.addEventListener('online', onOnline);
window.addEventListener('offline', onOffline);
if (isSupported) {
const connection = (navigator as any).connection;
connection.addEventListener('change', onConnectionChange);
updateNetworkInformation(); // 初始化數值
}
});
onUnmounted(() => {
if (typeof window === 'undefined') return;
window.removeEventListener('online', onOnline);
window.removeEventListener('offline', onOffline);
if (isSupported) {
const connection = (navigator as any).connection;
connection.removeEventListener('change', onConnectionChange);
}
});
return {
...state, // 展開屬性以便直接解構使用
state // 也保留 reactive 物件本身
};
}三、 實戰範例:智慧型圖片載入與斷線提示
這個範例展示如何根據網路狀況做兩件事:
- 斷線通知:當偵測到斷線時,顯示全域警告。
- 適應性載入:如果是弱網 (2g/slow-2g) 或開啟省流模式,載入低解析度圖片。
vue
<script setup lang="ts">
import { computed } from 'vue';
import { useNetwork } from '@/composables/useNetwork';
const { isOnline, effectiveType, saveData } = useNetwork();
// 判斷是否為弱網環境
const isSlowConnection = computed(() => {
return saveData || effectiveType === '2g' || effectiveType === 'slow-2g';
});
// 根據網速決定圖片來源
const imageUrl = computed(() => {
return isSlowConnection.value
? 'https://example.com/image-low-res.jpg' // 弱網:載入小圖
: 'https://example.com/image-high-res.jpg'; // 強網:載入大圖
});
</script>
<template>
<div class="network-demo">
<!-- 斷線警告 -->
<div v-if="!isOnline" class="offline-banner">
網路連接已中斷,目前顯示的是快取內容。
</div>
<div class="content">
<h3>網路狀態面板</h3>
<ul>
<li>連線狀態: <span :class="{ online: isOnline }">{{ isOnline ? '連線中' : '已離線' }}</span></li>
<li>連線類型: {{ effectiveType || '未知 (不支援)' }}</li>
<li>節省流量模式: {{ saveData ? '開啟' : '關閉' }}</li>
</ul>
<div class="image-wrapper">
<p>目前載入的是:{{ isSlowConnection ? '低畫質 (省流)' : '高畫質 (原始)' }} 版圖片</p>
<img :src="imageUrl" alt="Demo Image" />
</div>
</div>
</div>
</template>
<style scoped>
.offline-banner {
background: #ff4757;
color: white;
text-align: center;
padding: 10px;
position: sticky;
top: 0;
}
.online {
color: #2ed573;
font-weight: bold;
}
.network-demo {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
}
.content {
padding: 20px;
}
.image-wrapper img {
max-width: 100%;
border-radius: 4px;
margin-top: 10px;
}
</style>四、 開發者工具模擬測試
要測試這個功能,不需要真的拔網路線或跑到地下室。Chrome DevTools 提供了強大的模擬功能:
- 打開 DevTools (F12)。
- 切換到 Network 頁籤。
- 在上方工具列找到 No throttling 下拉選單。
- 選擇 Fast 3G, Slow 3G 或 Offline 來模擬各種網路情境。
當你切換時,navigator.connection 的 change 事件就會被觸發,你的 Vue 元件也應該即時反應。
總結
透過整合 onLine 事件與 Network Information API,我們可以讓網頁應用程式具備「網路感知 (Network Aware)」的能力。這對於打造漸進式網頁應用 (PWA) 或優化使用者在不同網路環境下的體驗至關重要。