cover

概念圖

什麼是 BOM?

你有沒有想過,為什麼 JavaScript 可以控制瀏覽器的網址列、偵測使用者的螢幕大小、甚至存取剪貼簿?這些都不是「網頁內容」的一部分,而是瀏覽器本身提供的能力。BOM 就是這座橋樑——搞懂它,你才真正掌握了「JavaScript 在瀏覽器裡能做到哪些事」。

BOM(Browser Object Model,瀏覽器物件模型)是瀏覽器提供的 API,讓 JavaScript 可以與瀏覽器本身互動,而不僅僅是網頁內容。

┌─────────────────────────────────────────────────┐
│                    window                        │
│  ┌───────────┐  ┌───────────┐  ┌───────────┐   │
│  │ document  │  │ location  │  │ navigator │   │
│  │  (DOM)    │  │  (URL)    │  │ (瀏覽器)  │   │
│  └───────────┘  └───────────┘  └───────────┘   │
│  ┌───────────┐  ┌───────────┐  ┌───────────┐   │
│  │  history  │  │  screen   │  │ localStorage│  │
│  │ (歷史)    │  │ (螢幕)    │  │ (儲存)     │   │
│  └───────────┘  └───────────┘  └───────────┘   │
└─────────────────────────────────────────────────┘

window 物件

window 是瀏覽器的全域物件,所有全域變數和函數都是它的屬性。

// 視窗尺寸
window.innerWidth;   // 視窗內部寬度(不含工具列)
window.innerHeight;  // 視窗內部高度
window.outerWidth;   // 視窗外部寬度(含工具列)
window.outerHeight;  // 視窗外部高度
 
// 視窗位置
window.screenX;      // 視窗左上角 X 座標
window.screenY;      // 視窗左上角 Y 座標
 
// 滾動位置
window.scrollX;      // 水平滾動距離
window.scrollY;      // 垂直滾動距離
window.pageXOffset;  // 同 scrollX
window.pageYOffset;  // 同 scrollY
 
// 滾動方法
window.scrollTo(0, 100);
window.scrollTo({ top: 100, behavior: 'smooth' });
window.scrollBy(0, 50);  // 相對滾動

對話框

// 警告框
alert('Hello!');
 
// 確認框
const confirmed = confirm('確定要刪除嗎?');
if (confirmed) { /* 執行刪除 */ }
 
// 輸入框
const name = prompt('請輸入姓名', '預設值');
 
// 注意:這些方法會阻塞 JavaScript 執行
// 現代應用通常使用自訂 Modal 代替

計時器

// setTimeout - 延遲執行(一次)
const timeoutId = setTimeout(() => {
  console.log('3 秒後執行');
}, 3000);
 
clearTimeout(timeoutId);  // 取消
 
// setInterval - 定期執行
const intervalId = setInterval(() => {
  console.log('每秒執行');
}, 1000);
 
clearInterval(intervalId);  // 取消
 
// requestAnimationFrame - 動畫用(約 60fps)
function animate() {
  // 更新動畫
  requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

開啟新視窗

// 開啟新視窗
const newWindow = window.open(
  'https://example.com',
  '_blank',
  'width=800,height=600'
);
 
// 關閉視窗
newWindow.close();
 
// 檢查視窗是否關閉
if (newWindow.closed) {
  console.log('視窗已關閉');
}

知道了 window 是什麼之後,你可能會想問:那網址列呢?怎麼用 JS 讀取或改變當前的 URL?這就是 location 的工作。

location 物件

location 包含當前 URL 的資訊,也可以用來導航。

// URL: https://example.com:8080/path/page.html?id=123#section
 
location.href;      // 完整 URL
location.protocol;  // "https:"
location.host;      // "example.com:8080"
location.hostname;  // "example.com"
location.port;      // "8080"
location.pathname;  // "/path/page.html"
location.search;    // "?id=123"
location.hash;      // "#section"
location.origin;    // "https://example.com:8080"
 
// 導航
location.href = 'https://example.com';  // 跳轉(會留下歷史)
location.assign('https://example.com'); // 同上
location.replace('https://example.com'); // 跳轉(不留歷史)
location.reload();  // 重新載入
location.reload(true);  // 強制從伺服器載入
 
// 解析 Query String
const params = new URLSearchParams(location.search);
params.get('id');      // "123"
params.has('id');      // true
params.set('id', '456');
params.toString();     // "id=456"

history 物件

history 提供瀏覽歷史的操作。

// 瀏覽歷史
history.length;      // 歷史記錄數量
history.back();      // 上一頁
history.forward();   // 下一頁
history.go(-2);      // 往前兩頁
history.go(1);       // 往後一頁
 
// HTML5 History API(SPA 路由用)
history.pushState({ page: 1 }, 'Title', '/page1');
history.replaceState({ page: 2 }, 'Title', '/page2');
 
// 監聽歷史變化
window.addEventListener('popstate', (event) => {
  console.log('State:', event.state);
});

OK,到目前為止我們學了怎麼控制視窗、操作網址和歷史紀錄。但有時候你需要知道的是使用者的環境——他用什麼瀏覽器?有沒有網路?這就是 navigator 的守備範圍。

navigator 提供瀏覽器和裝置資訊。

// 瀏覽器資訊
navigator.userAgent;   // 瀏覽器識別字串
navigator.language;    // 瀏覽器語言 "zh-TW"
navigator.languages;   // 偏好語言列表
navigator.platform;    // 作業系統平台
navigator.cookieEnabled;  // Cookie 是否啟用
navigator.onLine;      // 是否連線
 
// 監聯網狀態
window.addEventListener('online', () => console.log('上線了'));
window.addEventListener('offline', () => console.log('離線了'));
 
// 剪貼簿 API
await navigator.clipboard.writeText('複製的文字');
const text = await navigator.clipboard.readText();
 
// 地理位置 API
navigator.geolocation.getCurrentPosition(
  (position) => {
    console.log(position.coords.latitude);
    console.log(position.coords.longitude);
  },
  (error) => console.error(error)
);
 
// 震動 API(行動裝置)
navigator.vibrate(200);        // 震動 200ms
navigator.vibrate([100, 50, 100]);  // 震動模式
 
// 分享 API
if (navigator.share) {
  navigator.share({
    title: '標題',
    text: '內容',
    url: 'https://example.com'
  });
}

screen 物件

screen 提供螢幕資訊。

screen.width;        // 螢幕寬度
screen.height;       // 螢幕高度
screen.availWidth;   // 可用寬度(扣除工具列)
screen.availHeight;  // 可用高度
screen.colorDepth;   // 色彩深度
screen.pixelDepth;   // 像素深度
screen.orientation;  // 螢幕方向
 
// 監聽螢幕方向變化
screen.orientation.addEventListener('change', () => {
  console.log(screen.orientation.type);  // "portrait-primary" | "landscape-primary"
});

Storage API

// localStorage - 永久儲存
localStorage.setItem('key', 'value');
localStorage.getItem('key');
localStorage.removeItem('key');
localStorage.clear();
 
// sessionStorage - 分頁關閉即清除
sessionStorage.setItem('key', 'value');
 
// 儲存物件需要序列化
localStorage.setItem('user', JSON.stringify({ name: 'John' }));
const user = JSON.parse(localStorage.getItem('user'));
 
// 監聽儲存變化(跨分頁同步)
window.addEventListener('storage', (event) => {
  console.log(event.key, event.oldValue, event.newValue);
});

BOM vs DOM

項目BOMDOM
操作對象瀏覽器網頁內容
根物件windowdocument
標準化部分W3C 標準
功能視窗、導航、儲存元素操作、事件

延伸閱讀

MDN - Window DOM 瀏覽器機制 前後端傳接的那些資料