Pointer Lock API - Web APIs

Pointer Lock API
================

**實驗性質:** **這是一個實驗中的功能 (en-US)**
此功能在某些瀏覽器尚在開發中，請參考兼容表格以得到不同瀏覽器用的前輟。

**Pointer lock** (之前稱為 Mouse lock) 提供「隨時間經過所產生的滑鼠位移資訊 (即 deltas)」的輸入方法，而不只是滑鼠游標的絕對位置而已。此函式可存取基本的滑鼠位移、將滑鼠事件的目標鎖定至單一元素、讓滑鼠單一方向的位移距離不再受限、將游標移除到視點之外。

若 App 需要大量的滑鼠輸入以控制位移、旋轉物件、更改輸入項，那此 API 就特別有用。另對特別注重視覺效果的 App 尤其必要，如第一人稱視角、3D 視圖、模型建構等。

舉例來說，你可讓消費者不需點擊任何按鈕，只要透過滑鼠即可控制視角。而按鈕可用於其他動作。對於查看地圖、衛星圖像、第一人稱場景類 (如遊戲或虛擬實境影片) 的 App 來說，這種滑鼠輸入方式特別方便易用。

即使滑鼠游標移出瀏覽器或螢幕之外，Pointer lock 還是能讓你存取滑鼠事件。舉例來說，消費者還是可繼續移動滑鼠以旋轉或操作 3D 模型。若沒有 Pointer lock，則只要指標移出瀏覽器或螢幕之外，旋轉或操作隨即停止。遊戲玩家會特別喜歡此功能。他們現在可以隨便亂按按鈕並隨意滑動滑鼠；不再擔心滑鼠游標滑出遊戲區域而點到其他應用程式，結果退出遊戲發生慘案！

基本概念
----

Pointer lock 與 mouse capture 相關。在拖曳滑鼠時，Mouse capture 可持續向目標元素傳遞事件，且只要放開滑鼠按鈕隨即跟著停止。Pointer lock 與 mouse capture 不同之處在於：

* Pointer lock 屬持久性。除非發生顯式 (Explicit) API 呼叫，或使用者做出特定的釋放手勢，否則 Pointer lock 將不會釋放滑鼠。
* Pointer lock 不侷限於螢幕或瀏覽器的範圍。
* 不論滑鼠按鈕狀態為何，Pointer lock 將持續送出事件。
* Pointer lock 會隱藏游標。
範例
--

下列範例可讓你設定自己網頁上的 Pointer lock。

```js
<button onclick="lockPointer();">Lock it!</button>
<div id="pointer-lock-element"></div>
<script>
// Note: at the time of writing, only Mozilla and WebKit support Pointer Lock.

// The element we'll make fullscreen and pointer locked.
var elem;

document.addEventListener("mousemove", function(e) {
  var movementX = e.movementX       ||
                  e.mozMovementX    ||
                  e.webkitMovementX ||
                  0,
      movementY = e.movementY       ||
                  e.mozMovementY    ||
                  e.webkitMovementY ||
                  0;

  // Print the mouse movement delta values
  console.log("movementX=" + movementX, "movementY=" + movementY);
}, false);

function fullscreenChange() {
  if (document.webkitFullscreenElement === elem ||
      document.mozFullscreenElement === elem ||
      document.mozFullScreenElement === elem) { // Older API upper case 'S'.
    // Element is fullscreen, now we can request pointer lock
    elem.requestPointerLock = elem.requestPointerLock    ||
                              elem.mozRequestPointerLock ||
                              elem.webkitRequestPointerLock;
    elem.requestPointerLock();
  }
}

document.addEventListener('fullscreenchange', fullscreenChange, false);
document.addEventListener('mozfullscreenchange', fullscreenChange, false);
document.addEventListener('webkitfullscreenchange', fullscreenChange, false);

function pointerLockChange() {
  if (document.mozPointerLockElement === elem ||
      document.webkitPointerLockElement === elem) {
    console.log("Pointer Lock was successful.");
  } else {
    console.log("Pointer Lock was lost.");
  }
}

document.addEventListener('pointerlockchange', pointerLockChange, false);
document.addEventListener('mozpointerlockchange', pointerLockChange, false);
document.addEventListener('webkitpointerlockchange', pointerLockChange, false);

function pointerLockError() {
  console.log("Error while locking pointer.");
}

document.addEventListener('pointerlockerror', pointerLockError, false);
document.addEventListener('mozpointerlockerror', pointerLockError, false);
document.addEventListener('webkitpointerlockerror', pointerLockError, false);

function lockPointer() {
  elem = document.getElementById("pointer-lock-element");
  // Start by going fullscreen with the element. Current implementations
  // require the element to be in fullscreen before requesting pointer
  // lock--something that will likely change in the future.
  elem.requestFullscreen = elem.requestFullscreen    ||
                           elem.mozRequestFullscreen ||
                           elem.mozRequestFullScreen || // Older API upper case 'S'.
                           elem.webkitRequestFullscreen;
  elem.requestFullscreen();
}
</script>
```

函式/屬性概述
-------

Pointer lock API 與 Fullscreen API 類似，可添增 requestPointerLock (en-US) 新函式 (目前尚未標準化) 而擴充 DOM 元素。可為下列：

```js
element.webkitRequestPointerLock(); // Chrome
element.mozRequestPointerLock(); // Firefox
element.requestPointerLock(); // Standard
```

目前在建置 requestPointerLock (en-US) 時，還是必須緊密結合 requestFullScreen (en-US) 與 Fullscreen API。在指標鎖定某一元素之前，必須先進入全螢幕模式。如同上方的 Demo，指標鎖定屬於非同步程序，並透過 pointerlockchange 與 pointerlockerror 事件，指出該請求是否成功。此與 Fullscreen API 的運作方式相同 (使用其 requestFullScreen (en-US) 函式，另搭配 fullscreenchange 與 fullscreenerror 事件)。

Pointer lock API 另擴充了 and <table>) and provides functionality global to the document (suc">Document (en-US) 介面，同時添增了新的屬性與函式。如果目前有鎖定的元素，則新的屬性可存取該所訂元素，並命名為 pointerLockElement (en-US) (目前尚未標準化)。and <table>) and provides functionality global to the document (suc">Document (en-US) 上的新函式則為 exitPointerLock (en-US)；顧名思義，此函式可退出 Pointer lock。

pointerLockElement (en-US) 屬性可確定指標目前是否鎖定了任何元素 (例如進行 Boolean 檢查)。若確實有鎖定的元素，則可取得參考。以下為此二種用法的範例：

```js
document.pointerLockElement =
  document.pointerLockElement ||
  document.mozPointerLockElement ||
  document.webkitPointerLockElement;

// 1) Used as a boolean check: are we pointer locked?
if (!!document.pointerLockElement) {
  // pointer is locked
} else {
  // pointer is not locked
}

// 2) Used to access the pointer locked element
if (document.pointerLockElement === someElement) {
  // someElement is currently pointer locked
}
```

Document.exitPointerLock (en-US) 函式則用以退出 Pointer lock。且和 requestPointerLock (en-US) 一樣，Document.exitPointerLock (en-US) 是使用 pointerlockchange 與 pointerlockerror 事件，以非同步方式作業：

```js
document.exitPointerLock =
  document.exitPointerLock ||
  document.mozExitPointerLock ||
  document.webkitExitPointerLock;

function pointerLockChange() {
  document.pointerLockElement =
    document.pointerLockElement ||
    document.mozPointerLockElement ||
    document.webkitPointerLockElement;

  if (!!document.pointerLockElement) {
    console.log("Still locked.");
  } else {
    console.log("Exited lock.");
  }
}

document.addEventListener("pointerlockchange", pointerLockChange, false);
document.addEventListener("mozpointerlockchange", pointerLockChange, false);
document.addEventListener("webkitpointerlockchange", pointerLockChange, false);

// Attempt to unlock
document.exitPointerLock();
```

pointerlockchange 事件
--------------------

若 Pointer lock 狀態改變，如呼叫 requestPointerLock (en-US)、exitPointerLock (en-US)，或使用者按下 ESC 鍵等。則 pointerlockchange 事件隨即傳送至 `document`。此簡單事件不包含額外資料。

**備註：** 此事件目前在 Firefox 中的前綴為 `mozpointerlockchange`；在 Chrome 中的前綴為 `webkitpointerlockchange`。

pointerlockerror 事件
-------------------

當呼叫 requestPointerLock (en-US) 或 exitPointerLock (en-US) 而發生錯誤時，隨即傳送 pointerlockerror 事件至 `document`。此簡單事件不包含額外資料。

**備註：** 此事件在 Firefox 中的前綴為 `mozpointerlockerror`；在 Chrome 中的前綴為 `webkitpointerlockerror`。

擴充至滑鼠事件
-------

Pointer lock API 可透過位移屬性而擴充標準的 MouseEvent (en-US) 介面。
```

partial interface MouseEvent {
    readonly attribute long movementX;
    readonly attribute long movementY;
};
```

**備註：** 位移屬性目前在 Firefox 中的前綴為 `.mozMovementX` 與 `.mozMovementY`；在 Chrome 中的前綴為`.webkitMovementX` 與 `.webkitMovementY`。

滑鼠事件的二個新參數 (即 movementX (en-US) 與 movementY (en-US)) 將提供滑鼠位置的變化情形。此二項參數的值，等於 MouseEvent (en-US) 屬性值 (即 screenX (en-US) 與 screenY (en-US)) 之間的變化；而 MouseEvent (en-US) 屬性另儲存於二項連續的 mousemove 事件 (即 eNow 與 ePrevious) 之內。換句話說，Pointer lock 參數 `movementX = eNow.screenX - ePrevious.screenX`。

### 鎖定狀態

在啟動 Pointer lock 之後，標準的 MouseEvent (en-US) 屬性 clientX (en-US)、clientY (en-US)、screenX (en-US)、screenY (en-US) 均維持不變，如同滑鼠沒有移動。movementX (en-US) 與 movementY (en-US) 屬性將持續提供滑鼠的位置變化。如果滑鼠朝單一方向持續移動，movementX (en-US) 與 movementY (en-US) 的值也就不受限。此時「滑鼠游標」的概念不存在，游標無法移出視窗之外，也不會受限於螢幕邊界。

### 未鎖定狀態

無論滑鼠的鎖定狀態為何，movementX (en-US) 與 movementY (en-US) 參數均保持有效；另為了方便起見，甚至在未鎖定狀態下仍可保持有效。

在解鎖滑鼠之後，系統游標可退出並重新進入瀏覽器視窗，且 movementX (en-US) 與 movementY (en-US) 此時可能設定為零。

iframe 限制
---------

Pointer lock 一次僅能鎖定一組 iframe。在鎖定一組 iframe 之後，就無法鎖定另一組 iframe 並轉移目標至該 iframe 之上；Pointer lock 將發生錯誤。為擺脫此限制，必須先將鎖定的 iframe 解鎖，再鎖定另一組 iframe。

由於 iframes 是根據預設值運作，因此預設為「沙箱式 (sandboxed)」的 iframes 將阻擋 Pointer lock。為擺脫此限制，Chrome 應該很快就會推出 `<iframe sandbox="allow-pointer-lock">` 的「屬性/值」整合形式。

規格
--

| Specification |
| --- |
| Pointer Lock 2.0  |

瀏覽器相容性
------

### api.Document.exitPointerLock

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.Element.requestPointerLock

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

另可參閱
----

* `MouseEvent` (en-US)


AbortController - Web APIs

AbortController
===============

**實驗性質:** **這是一個實驗中的功能 (en-US)**
此功能在某些瀏覽器尚在開發中，請參考兼容表格以得到不同瀏覽器用的前輟。

**`AbortController`** 介面代表一個控制器物件，讓你可以在需要時中斷一個或多個 DOM 請求。

你可以使用 `AbortController.AbortController()` (en-US) 建立一個新的 `AbortController` 物件。與 DOM 請求溝通時則是使用 `AbortSignal` (en-US) 物件。

建構子
---

`AbortController.AbortController()` (en-US)

建立一個新的 `AbortController` 物件實體。

屬性
--

`AbortController.signal` (en-US) Read only

回傳一個 `AbortSignal` (en-US) 物件實體，可以用來中斷一個 DOM 請求、或是與其溝通。

方法
--

`AbortController.abort()` (en-US)

在一個 DOM 請求完成前中斷他。這可以用來中斷 fetch 請求 (en-US)、對任何 Response `Body` 的讀取、或是資料流。

範例
--

在下面的程式碼片段中，我們要用 Fetch API 來下載一部影片。

我們首先用 `AbortController()` (en-US) 建立一個控制器，然後透過 `AbortController.signal` (en-US) 屬性取得他的 `AbortSignal` (en-US) 物件。

在初始化 fetch 請求 (en-US) 的時候，我們把 `AbortSignal` 作為選項傳入該請求的選項物件中（參考下方的 `{signal}`）。這樣會把剛才的中斷訊號與控制器跟 fetch 請求關聯起來，讓我們可以透過呼叫 `AbortController.abort()` (en-US) 來中斷該請求。請參考下方範例中第二個事件處理器。

```js
var controller = new AbortController();
var signal = controller.signal;

var downloadBtn = document.querySelector('.download');
var abortBtn = document.querySelector('.abort');

downloadBtn.addEventListener('click', fetchVideo);

abortBtn.addEventListener('click', function() {
  controller.abort();
  console.log('下載已中斷');
});

function fetchVideo() {
  ...
  fetch(url, {signal}).then(function(response) {
    ...
  }).catch(function(e) {
    reports.textContent = '下載錯誤: ' + e.message;
  })
}
```

**備註：** 當 `abort()` 被呼叫的時候，`fetch()` 回傳的 Promise 會被以 `AbortError` 拒絕。

在 GitHub 有個完整的範例可供參考 — 請參見 abort-api（或是也可以實際體驗看看）。

規格
--

| Specification |
| --- |
| DOM Standard # interface-abortcontroller |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* Fetch API
* Abortable Fetch by Jake Archibald


DOMTokenList - Web APIs

DOMTokenList
============

**`DOMTokenList`** 介面表示了一個以空格作為分隔的內容集，通常來自 `Element.classList` (en-US)、`HTMLLinkElement.relList` (en-US)、`HTMLAnchorElement.relList` (en-US) 或 `HTMLAreaElement.relList` (en-US) 等屬性。本介面與 `Array` 同樣是由 `0` 開始索引，且 `DOMTokenList` 是區分大小寫的。

屬性
--

*This interface doesn't inherit any property.*

`DOMTokenList.length` (en-US) Read only

Is an `integer` representing the number of objects stored in the object.

方法
--

*This interface doesn't inherit any method.*

`DOMTokenList.item()` (en-US)

Returns an item in the list by its index (or undefined if the number is greater than or equal to the length of the list, prior to Gecko 7.0 returned null)

`DOMTokenList.contains()` (en-US)

Returns `true` if the underlying string contains *token*, otherwise `false`

`DOMTokenList.add()` (en-US)

Adds *token* to the underlying string

`DOMTokenList.remove()` (en-US)

Removes *token* from the underlying string

`DOMTokenList.replace()` (en-US)

Replaces an existing *token* with a new token.

`DOMTokenList.supports()` (en-US)

Returns `true` if a given *token* is in the associated attribute's supported tokens.

`DOMTokenList.toggle()` (en-US)

Removes *token* from string and returns false. If *token* doesn't exist it's added and the function returns true

規範
--

| Specification |
| --- |
| DOM Standard # interface-domtokenlist |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `DOMSettableTokenList` (object that extends DOMTokenList with settable *.value* property)


Media Capture and Streams API (Media Stream) - Web APIs

Media Capture and Streams API (Media Stream)
============================================

該**媒體捕獲和流**API，通常被稱為**媒體流 API**或者乾脆**MediaStream API**，是關係到一個 API的 WebRTC (en-US)提供流式音頻和視頻數據的支持。它提供了用於處理流及其組成軌道的接口和方法，與數據格式關聯的約束，異步使用數據時的成功和錯誤回調以及在此過程中觸發的事件。

概念和用法
-----

該 API 基於`MediaStream` (en-US)對象的操作，該對象代表與音頻或視頻相關的數據流。請參閱「獲取視頻 (en-US)」中的示例。

A `MediaStream` consists of zero or more `MediaStreamTrack` (en-US) objects, representing various audio or video **tracks**. Each `MediaStreamTrack` may have one or more **channels**. The channel represents the smallest unit of a media stream, such as an audio signal associated with a given speaker, like *left* or *right* in a stereo audio track.

`MediaStream` objects have a single **input** and a single **output**. A `MediaStream` object generated by `getUserMedia()` (en-US) is called *local*, and has as its source input one of the user's cameras or microphones. A non-local `MediaStream` may be representing to a media element, like `<video>` (en-US) or `<audio>` (en-US), a stream originating over the network, and obtained via the WebRTC `RTCPeerConnection` (en-US) API, or a stream created using the Web Audio API `MediaStreamAudioSourceNode` (en-US).

The output of the `MediaStream` object is linked to a **consumer**. It can be a media elements, like `<audio>` (en-US) or `<video>` (en-US), the WebRTC `RTCPeerConnection` (en-US) API or a Web Audio API `MediaStreamAudioSourceNode` (en-US).

Interfaces
----------

In these reference articles, you'll find the fundamental information you'll need to know about each of the interfaces that make up the Media Capture and Streams API.

* `BlobEvent` (en-US)
* `CanvasCaptureMediaStreamTrack` (en-US)
* `InputDeviceInfo` (en-US)
* `MediaDeviceKind`
* `MediaDeviceInfo` (en-US)
* `MediaDevices`
* `MediaStream` (en-US)
* `MediaStreamConstraints` (en-US)
* `MediaStreamEvent` (en-US)
* `MediaStreamTrack` (en-US)
* `MediaStreamTrackEvent` (en-US)
* `MediaTrackCapabilities`
* `MediaTrackConstraints` (en-US)
* `MediaTrackSettings` (en-US)
* `MediaTrackSupportedConstraints` (en-US)
* `NavigatorUserMedia`
* `NavigatorUserMediaError`
* `OverconstrainedError` (en-US)
* `URL` (en-US)

Early versions of the Media Capture and Streams API specification included separate `AudioStreamTrack` and `VideoStreamTrack` interfaces—each based upon `MediaStreamTrack` (en-US)—which represented streams of those types. These no longer exist, and you should update any existing code to instead use `MediaStreamTrack` directly.

Events
------

* `addtrack` (en-US)
* `ended` (en-US)
* `mute` (en-US)
* `overconstrained` (en-US)
* `removetrack` (en-US)
* `unmute` (en-US)
Guides and tutorials
--------------------

The articles below provide additional guidance and how-to information that will help you learn to use the API, and how to perform specific tasks that you may wish to handle.

Browser compatibility
---------------------

### api.MediaStream

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.MediaStreamTrack

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.MediaDevices

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.MediaDeviceInfo

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.InputDeviceInfo

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.CanvasCaptureMediaStreamTrack

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

也可以看看
-----

* WebRTC (en-US) -API 簡介頁
* `mediaDevices.getUserMedia()` (en-US)
* 使用 WebRTC 拍攝靜態照片 (en-US)：有關使用`getUserMedia()`。


Notifications API - Web APIs

Notifications API
=================

Notifications API 允許網頁控制向終端用戶顯示系統通知 — 它在網頁瀏覽器的視圖之外，因此使用者切換顯示卡或移至不同的應用程式也能顯示。此 API 設計為在相容於不同平台與現有的通知系統相容。

概念與使用方法
-------

在受到支持的平台上，顯示系統通知通常涉及兩件事。 首先，用戶需要授予當前的來源權限才能顯示系統通知，通常在應用程式或網站初始化完成後使用`Notification.requestPermission()` (en-US) 方法。

```js
btn.addEventListener("click", function () {
  let promise = Notification.requestPermission();
  // wait for permission
});
```

這不僅是最佳實踐 — 你不應向用戶發送他們不同意的通知，並且在未來瀏覽器將明確禁止沒有響應用戶請求允許通知對話框的通知。Firefox 72 開始已遵循這項約定。使用此方法將產生一個請求對話框，如下所示：

![](/zh-TW/docs/Web/API/Notifications_API/screen_shot_2019-12-11_at_9.59.14_am.png)

用戶可以從此處選擇允許、屏蔽來自此來源的通知，也可以不做選擇。 一旦選定，該設置通常將在當前會話中保持不變。

**備註：** 從 Firefox 44 開始，Notifications 和 Push (en-US) 的權限已合併。如果授予通知權限則推送也將被啟用。

下一步，使用 `Notification()` (en-US) 構造函數創建一個新通知。 這必須要傳遞一個標題參數(title)，並且可以選擇性的傳遞選擇物件指定諸如文字方向、正文、圖標、撥放通知的聲音等等。

**備註：** 此功能可在 Web Worker (en-US) 中使用

另外，Notifications API 規範指定了 ServiceWorker API (en-US) 的許多附加功能，以允許服務人員觸發通知。

**備註：** 要了解有關在自己的應用程序中使用通知的更多信息，請閱讀 Using the Notifications API。

Notifications 介面
----------------

`Notification`

定義一個通知物件。

### Service worker 附加功能

`ServiceWorkerRegistration` (en-US)

包含 `ServiceWorkerRegistration.showNotification()` (en-US) 和 `ServiceWorkerRegistration.getNotifications()` (en-US) 用於控制通知顯示的方法。

`ServiceWorkerGlobalScope` (en-US)

包含 `ServiceWorkerGlobalScope.onnotificationclick` 點擊通知時觸發自定義函數的處理程序。

`NotificationEvent` (en-US)

基於 `ExtendableEvent` (en-US) 的特定類型的事件對象，它表示已觸發的通知。

規範
--

| Specification |
| --- |
| Notifications API Standard  |

瀏覽器相容性
------

### api.Notification

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.ServiceWorkerRegistration.showNotification

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.ServiceWorkerRegistration.getNotifications

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Firefox OS permissions
----------------------

When using notifications in a Firefox OS app, be sure to add the `desktop-notification` permission in your manifest file. Notifications can be used at any permission level, hosted or above:

```json
"permissions": {
  "desktop-notification": {}
}
```

參見
--

* Using the Notifications API


TouchList - Web APIs

TouchList
=========

`TouchList` 介面表示了一個觸控平面上所有觸碰點的列表；舉例來說，假如使用者有三隻手指於觸控平面（如觸控螢幕或是觸控板）上，則其相對應的 `TouchList` 物件中就會分別有三個 `Touch` (en-US) 物件各代表一個手指的觸碰。

屬性
--

`TouchList.length` (en-US) Read only

The number of `Touch` (en-US) objects in the `TouchList`.

方法
--

`TouchList.identifiedTouch()`
已棄用

Returns the first `Touch` (en-US) item in the list whose identifier matches a specified value.

`TouchList.item()` (en-US)

Returns the `Touch` (en-US) object at the specified index in the list.

範例
--

See the example on the main Touch events article (en-US).

規範
--

| Specification |
| --- |
| Touch Events # touchlist-interface |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* Touch events (en-US)
* `Document.createTouchList()` (en-US)


WheelEvent - Web APIs

WheelEvent
==========

WheelEvent DOM 事件會在用戶滚动滑鼠滚轮或操作其它類似滑鼠的設備時觸發。

**警告：** 該事件爲標準規定的事件介面。早期的瀏覽器實現過 `MouseWheelEvent` (en-US) 和 `MouseScrollEvent` (en-US) 兩種滾輪事件介面，但這兩種介面皆非標準，加之各瀏覽器間對其相容性極差。因而開發者應用該標準事件介面取代這兩個非標準介面。

**備註：** 請勿想當然依據滾輪方向（即該事件的各 delta 屬性值）來推斷文檔內容的滾動方向，因標準未定義滾輪事件具體會引發什麼樣的行爲，引發的行爲實際上是各瀏覽器自行定義的。即便滾輪事件引發了文檔內容的滾動行爲，也不表示滾輪方向和文檔內容的滾動方向一定相同。因而通過該滾輪事件獲知文檔內容滾動方向的方法並不可靠。要獲取文檔內容的滾動方向，可在文檔內容滾動事件（`scroll` (en-US)）中監視 `scrollLeft` (en-US) 和 `scrollTop` 二值變化情況，即可推斷出滾動方向了。

Event

UIEvent

MouseEvent

(en-US)

WheelEvent建構式
---

`WheelEvent()` (en-US)

建立一個 `WheelEvent` 物件。

屬性
--

*該介面繼承了父介面 `MouseEvent` (en-US)、`UIEvent`、`Event` 的屬性。*

`WheelEvent.deltaX` (en-US) Read only

返回 `double` 值，該值表示滾輪的橫向滾動量。

`WheelEvent.deltaY` (en-US) Read only

返回 `double` 值，該值表示滾輪的縱向滾動量。

`WheelEvent.deltaZ` (en-US) Read only

返回 `double` 值，該值表示滾輪的 z 軸方向上的滾動量。

`WheelEvent.deltaMode` (en-US) Read only

返回 `unsigned long` 值，該值表示上述各 delta 的值的單位。該值及所表示的單位如下：

| 常數 | 值 | 描述 |
| --- | --- | --- |
| `DOM_DELTA_PIXEL` | `0x00` | 滾動量單位爲像素。 |
| `DOM_DELTA_LINE` | `0x01` | 滾動量單位爲行。 |
| `DOM_DELTA_PAGE` | `0x02` | 滾動量單位爲頁。 |

方法
--

*該介面本身未定義方法，但繼承了父介面 `MouseEvent` (en-US)、`UIEvent`、`Event` 的方法。*

規範
--

| Specification |
| --- |
| UI Events # interface-wheelevent |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `wheel` (en-US)
* 該介面取代的過時介面：
    + `MouseScrollEvent` (en-US)（Gecko 內核瀏覽器）
    + `MouseWheelEvent` (en-US)（非 Gecko 內核的瀏覽器）


FileHandle API - Web APIs

FileHandle API
==============

FileHandle API 可操作檔案，例如建立檔案、修改檔案內容 (不同於 File (en-US) API)。而正在編輯中的部分，將使用回合制的鎖定機制，以避免發生競態 (Race) 問題。

API
---

### 建立 FileHandle

若要建立 FileHandle 物件，則需要 IndexedDB Database (en-US)。
```

var idbreq = indexedDB.open("MyTestDatabase");

idbreq.onsuccess = function () {
  var db = idbreq.result;
  var handleReq = db.mozCreateFileHandle("test.bin", "binary");

  handleReq.onsuccess = function () {
    var handle = handleReq.result;
    console.log("handle", handle);
  };
};
```

`mozCreateFileHandle()` 共使用 `2` 組參數(Argument)：1 組名稱與 1 組檔案類別 (Optional type)。但這 2 組參數均只屬於敘述性參數，不會用於資料庫。舉例來說，名稱可能是空白字串，而且不需為專屬字串。所以 API 根本不會注意這些參數值。

另請注意，上列程式碼僅會建立「暫時性檔案」，亦即當你保留 FileHandle 物件時，該檔案才會存在。如果你要在重新整理頁面/重新啟動 App 之後，仍能保留檔案，則必須將 Handle 儲存於更永久性的位置 (如資料庫本身之內) 中。

```js
var transaction = db.transaction(["test"], "readwrite");
var objectStore = transaction.objectStore("test");
objectStore.add(myFile, myKey).onsuccess = function (event) {
  // The file is now referenced from database too.
};
```

### FileHandle 介面
```

interface FileHandle
{
  LockedFile open(optional DOMString mode);
  DOMRequest getFile()
  readonly attribute DOMString name;
  readonly attribute DOMString type;
  attribute Function? onabort;
  attribute Function? onerror;
};
```

open([mode="readonly"])

可回傳 LockedFile。`mode` 可為「`readonly`」或「`readwrite`」。

getFile()

針對檔案而回傳 DOMRequest。若成功，就會收到以 File (en-US) 物件形式呈現的唯讀「snapshot」檔案內容 (可用於任何接受 Blob (en-US) 的地方，如 FileReader (en-US) 或 XMLHttpRequest 等)。

```js
myFile.getFile().onsuccess = function (event) {
  var file = event.target.result;
  var transcation = myDatabase.transaction(["snapshots"], "readwrite");
  var objectStore = transaction.objectStore("snapshots");
  objectStore.add(file, snapshotKey).onsuccess = function (event) {
    // A new readonly copy of the file has been created.
  };
};
```

name

檔案名稱。

type

代表 content-type。

abort event

放棄已鎖定的檔案，就會發生此事件。

error event

任何內部錯誤，都會發生此事件。

### LockedFile 介面
```

interface LockedFile
{
  readonly attribute FileHandle fileHandle;
  readonly attribute DOMString mode;
  readonly attribute boolean active;
  attribute any? location;
  FileRequest getMetadata(optional FileMetadataParameters parameters);
  FileRequest readAsArrayBuffer(unsigned long long size);
  FileRequest readAsText(unsigned long long size, optional DOMString encoding);
  FileRequest write(DOMString or ArrayBuffer or Blob value);
  FileRequest append(DOMString or ArrayBuffer or Blob value);
  FileRequest truncate(optional unsigned long long size);
  FileRequest flush();
  void abort();
  attribute Function? oncomplete;
  attribute Function? onabort;
  attribute Function? onerror;
};
```

fileHandle

來自於解鎖的 FileHandle 物件。

mode

「`readonly`」或「`readwrite`」。

active

一旦建立之後，就隨即啟動 LockedFile。此 LockedFile 是「可寫入存取 (Write access) 實際底層檔案」的唯一物件。LockedFile 上的作業，均於 isolation 之中執行；也就是說，只要啟動了 LockedFile，則此 LockedFile 的所有作業都一定會在底層檔案上依序執行，而不會與其他 LockedFiles 的作業交錯執行。

若停用了 LockedFile，則只要在同樣的 LockedFile 上執行讀/寫作業，都會丟出錯誤訊息。

location

檔案中的位置 (Offset)。每次讀/寫作業之後，此數值均將自動變更。讀寫作業均從該 location 開始，而 null 代表檔案末端。

getMetadata(parameters)

針對後設資料 (Metadata) 而回傳 FileRequest (en-US)。此參數亦屬於物件，其中將參數名稱作為物件鍵值，布林值作為數值，進而非同步檢索既有的屬性。無數值則代表 `true`。目前僅有 `size` 與 `lastModified` 為可能的參數。

readAsArrayBuffer(size)

針對既有 `size` 的 ArrayBuffer，回傳 FileRequest (en-US)。此作業均從 `location` 開始，另根據讀取位元組的數目，移動 `location`。

readAsText(size [, encoding])

針對既有 `size` 的字串，以既定的 `encoding` 回傳 FileRequest (en-US)。此作業均從 `location` 開始，另根據讀取位元組的數目，移動 `location`。FileReader (en-US) API 中的對等函式，也以相同方式運作。

```js
var lockedFile = myFile.open();
var request = lockedFile.readAsText(3);
request.onsuccess = function (event) {
  var text = request.result;
  // 3 characters have been read.
};
```

write(value)

針對成功/失敗的寫入作業，回傳 FileRequest (en-US)。寫入作業將從 `location` 開始，另根據寫入位元組的數目，移動位置。

```js
var lockedFile = myFile.open("readwrite");
var request = lockedFile.write("foo");
request.onsuccess = function (event) {
  // The string "foo" has been written.
};
```

append(value)

針對成功/失敗的附加 (Append) 作業，回傳 FileRequest (en-US)。不論 `location` 為何，該數值均附加於檔案末端。在附加資料完畢後，`location` 隨即設定為 `null`。

truncate([size])

針對成功/失敗的截斷 (Truncate) 作業，回傳 FileRequest (en-US)。

如果是以單一參數呼叫該函式，則截斷成功之後，則**不論** `location` 為何，檔案將剩下第一個 `size` 的位元組。

若沒有用任何參數呼叫該函式，則檔案將剩下 `location` 的第一個位元組。

flush()

強制移轉緩衝過的資料至磁碟上，作業成功之後將回傳 FileRequest。此時即便 App 當機或非刻意中止，都能確保資料已經位於磁碟上了。

abort()

停用 LockedFile 並取消全部尚未執行的作業。

### FileRequest 介面

此類型的物件，均是由 LockedFile 介面的所有非同步作業所回傳。此介面繼承了 DOMRequest 並類似 IDBRequest (en-US)，同時還擁有 `onprogress` 事件。在成功之後，則可透過 `result` 屬性而取得必要檔案作業的結果。
```

interface FileRequest : DOMRequest
{
  readonly attribute LockedFile lockedFile;
  attribute Function? onprogress;
};
```

說明
--

### API 與 FileWriter 的差異？

FileWriter 規格定義了 FileWriter，也就是用以呈現「可編輯的檔案」的物件。Public-webapps 討論串則下了結論：若單一檔案同時寫入不同的實體 (Entity)，將導致 API 成效不彰。最後就是 FileHandle API 應具備自己的 LockedFile 與交易機制。


ErrorEvent - Web APIs

ErrorEvent
==========

**`ErrorEvent`** 介面是用來提供程式碼或是檔案的錯誤訊息的事件。

Properties
----------

*此介面繼承了其父 `Event` 的 properties 。*

`ErrorEvent.message` Read only

一 `DOMString` 提供具可讀性的關於問題的錯誤訊息。

`ErrorEvent.filename` Read only

一 `DOMString` ，為發生錯誤的程式碼檔案的檔名。

`ErrorEvent.lineno` Read only

一 `整數` ，為發生問題的程式的行數。

`ErrorEvent.colno` Read only

一 `整數` ，為發生問題的程式的欄數。

`ErrorEvent.error` Read only
實驗性質

一個參與該事件的 JavaScript `Object` 。

Constructor
-----------

`ErrorEvent()`

建立一 `ErrorEvent` 事件，其包含提供的參數。

Methods
-------

*此介面繼承了其父 `Event` 的 methods。*

Specifications
--------------

| Specification |
| --- |
| HTML Standard # the-errorevent-interface |

瀏覽器支援度比較
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

延伸閱讀
----

* Using web workers (en-US), most likely objects to raise such an event


Geolocation - Web APIs

Geolocation
===========

**`Geolocation`** 介面代表一個物件可以透過你的網頁程式去獲得你的裝置位置。這個介面提供了網站或應用程式根據使用者的位置去客製化呈現的內容。

`Navigator` (en-US) 此物件實作了 `Navigator.geolocation` 介面。

**備註：** 因為隱私的因素，當網頁要求存取位置資訊時，用戶會被提示通知並且詢問授權與否。注意不同的瀏覽器在詢問授權時有各自不同的策略和方式。

性質
--

*`Geolocation` 介面沒有繼承也沒有時做任何方法*。

方法
--

**`Geolocation` 介面沒有繼承任何方法**。

`Geolocation.getCurrentPosition()`

取得裝置當前位置，並回傳`Position`。

`Geolocation.watchPosition()`

返回一個長整數，註冊一個回呼函數。這個方法是用來註冊一個處理的函式，當使用者的裝置位置更新時，這個函式所傳入的回呼函式(callback function) 就會自動被呼叫。

`Geolocation.clearWatch()`

移除指定註冊的 `watchPosition()`。

規格
--

| Specification |
| --- |
| Geolocation API # geolocation\_interface |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

請參考
---

* Using geolocation (en-US)


History - Web APIs

History
=======

**`History`** 介面允許操控瀏覽器的 *session history* 紀錄，為當前面頁所在分頁中訪問、或於當前面頁中透過頁面框架（frame）所載入的頁面。

屬性
--

*The `History`* *interface doesn't inherit any property.*

`History.length` (en-US) Read only

Returns an `Integer` representing the number of elements in the session history, including the currently loaded page. For example, for a page loaded in a new tab this property returns `1`.

`History.current` Read only
非標準

已棄用

Returns a `DOMString` representing the URL of the active item of the session history. This property was never available to web content and is no more supported by any browser. Use `Location.href` (en-US) instead.

`History.next` Read only
非標準

已棄用

Returns a `DOMString` representing the URL of the next item in the session history. This property was never available to web content and is not supported by other browsers.

`History.previous` Read only
非標準

已棄用

Returns a `DOMString` representing the URL of the previous item in the session history. This property was never available to web content and is not supported by other browsers.

`History.scrollRestoration` (en-US)
實驗性質

Allows web applications to explicitly set default scroll restoration behavior on history navigation. This property can be either `auto` or `manual`.

`History.state` (en-US) Read only

Returns an `any` value representing the state at the top of the history stack. This is a way to look at the state without having to wait for a `popstate` event.

方法
--

*The `History`* *interface doesn't inherit any methods.*

`History.back()` (en-US)

回到 session history 紀錄中的前一頁，等同於使用者按下瀏覽器的上一頁按鈕。相當於 `history.go(-1)`。

**備註：** Calling this method to go back beyond the first page in the session history has no effect and doesn't raise an exception.

`History.forward()` (en-US)

回到 session history 紀錄中的下一頁，等同於使用者按下瀏覽器的下一頁按鈕。相當於 `history.go(1)`。

**備註：** Calling this method to go forward beyond the most recent page in the session history has no effect and doesn't raise an exception.

`History.go()` (en-US)

自 session history 紀錄中載入一個頁面，利用該頁面相對於目前頁面的所在位置，例如 -1 為前一頁或 1 為下一頁。若指定了一個超出範圍的值（舉例來說，在 session history 沒有先前訪頁面的情況下指定 -1），此方法將會是靜默（不會產生錯誤）且沒有任何效果的。不帶參數或是傳入 0 呼叫 `go()` 會重新載入目前頁面。Internet Explorer 也可以傳入字串來前往一個於瀏覽歷史列表中指定的頁面。

`History.pushState()` (en-US)

插入給定的資料與指定的標題（title）以及選擇性的 URL 至 session history 堆疊（stack）中。給定的資料將被 DOM 視為不透明的（opaque）；可以指定任何可被序列化的 JavaScript 物件。請注意 Firefox 目前會忽略標題（title）參數；更多資訊請參閱操控瀏覽器歷史紀錄。

`History.replaceState()` (en-US)

以指定的資料、標題（title）及可選的 URL 來更新歷史紀錄堆疊（history stack）中近期的項目。給定的資料將被 DOM 視為不透明的（opaque）；可以指定任何可被序列化的 JavaScript 物件。請注意 Firefox 目前會忽略標題（title）參數；更多資訊請參閱操控瀏覽器歷史紀錄。

規範
--

| Specification |
| --- |
| HTML Standard # the-history-interface |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* The `Window.history` (en-US) property returning the history of the current session.


File - Web APIs

File
====

**`File`** 介面提供了檔案的資訊並且允許網頁中的 JavaScript 存取檔案的內容。

`File` 物件通常是從使用者於 `<input>` (en-US) 元素選擇之檔案所回傳的 `FileList` 物件當中取得，也可以來自拖放操作所產生的 `DataTransfer` (en-US) 物件之中，或是由 `HTMLCanvasElement` (en-US) 物件（元素物件）執行 `mozGetAsFile()` 方法後回傳。在 Gecko 引擎中，有專屬的程式碼能不需使用者操作即建立 `File` 物件來表示本地端的任一檔案（請參考 Implementation notes 以閱讀更多資訊）。

`File` 物件是一種特殊的 `Blob`，且可被用在任何接受 Blob 物件的地方。特別是 `FileReader`、`URL.createObjectURL()` (en-US)、`createImageBitmap()` (en-US) 和 `XMLHttpRequest.send()` 都能夠同樣接受 `Blob` 以及 `File`。

請參考在網頁應用程式中使用本地檔案的更多細節與範例。

Blob

File建構式
---

`File()`

回傳一個新建構的 `File` 物件。

屬性
--

`File.lastModified` (en-US) Read only

回值檔案的最後修改時間，為 UNIX epoch 毫秒（自西元 1970 年一月 1 日零時至今）。

`File.lastModifiedDate` (en-US) Read only
已棄用

`File` 物件所代表之檔案的最後修改日期（`Date`）。

`File.name` Read only

`File` 物件所代表之檔案的名稱。

`File.size` (en-US) Read only

回傳檔案大小。

`File.webkitRelativePath` (en-US) Read only
非標準

回傳相對於 `File` 的網址位置。

`File.type` (en-US) Read only

回傳檔案的 MIME 類型。

`File` 實作了 `Blob`，因此它也有以下可用屬性：

`File.size` (en-US) Read only

回傳檔案大小（單位為位元組）。

`File.type` (en-US) Read only

回傳檔案的 MIME (en-US) 類型。

方法
--

*`File` 介面沒有定義任何方法，但繼承了 `Blob` 介面的方法：*

`Blob.slice([start[, end[, contentType]]])` (en-US)

回傳新的 `Blob` 物件，包含 `Blob` 來源之指定位元組範圍的資料。

規範
--

| Specification |
| --- |
| File API # file-section |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### 實作備註

* In Gecko, you can use this API from within chrome code. See Using the DOM File API in chrome code for details. To use it from chrome code, JSM and Bootstrap scope, you have to import it using `Cu.importGlobalProperties(['File']);`
* Starting from Gecko 6.0, privileged code (such as extensions) can pass an `nsIFile` object to the DOM `File` constructor to specify the file to reference.
* Starting from Gecko 8.0, you can use `new File` to create `File` objects from XPCOM component code instead of having to instantiate the `nsIDOMFile` object directly. The constructor takes, in contrast to `Blob`, as second argument the filename. The filename can be any String.
```

new File(
  Array parts,
  String filename,
  BlobPropertyBag properties
);
```

* The following non-standard properties and methods were removed in Gecko 7: `File.fileName`, `File.fileSize` (en-US), `File.getAsBinary()`, `File.getAsDataURL()`, `File.getAsText(string encoding)` (Firefox bug 661876). Standard properties `File.name`, `Blob.size`, and methods on `FileReader` should be used instead.
參見
--

* 在網頁應用程式中使用本地檔案
* `FileReader`
* Using the DOM File API in chrome code (for privileged code running in Gecko, such as Firefox add-ons)


Network Information API - Web APIs

Network Information API
=======================

**實驗性質:** **這是一個實驗中的功能 (en-US)**
此功能在某些瀏覽器尚在開發中，請參考兼容表格以得到不同瀏覽器用的前輟。

Network Information API 將提供系統連線的相關資訊，如使用者裝置的現有頻寬，或目前的連線狀態。根據使用者的連線情形，可進一步選擇高解析度或低解析度的內容。此完整的 API 另包含 domxref("Connection") 介面，以及 `Navigator` (en-US) 介面的單一屬性 ─ `Navigator.connection` (en-US)。

偵測連線變化
------

此範例將觀察使用者連線的變化。舉例來說，當使用者從高價位連線轉用低價位連線時，就會降低頻寬需求以避免連線費用暴增，並採用類似 Apps 受到警示的方法。

```js
var connection =
  navigator.connection || navigator.mozConnection || navigator.webkitConnection;

function updateConnectionStatus() {
  alert("Connection bandwidth: " + connection.bandwidth + " MB/s");
  if (connection.metered) {
    alert("The connection is metered!");
  }
}

connection.addEventListener("change", updateConnectionStatus);
updateConnectionStatus();
```

規範
--

| Specification |
| --- |
| Network Information API # networkinformation-interface |
| Network Information API # connection-attribute |

瀏覽器相容性
------

### api.NetworkInformation

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.Navigator.connection

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Network Information API Specification
* 線上與離線事件
* `window.navigator.connection`


Fetch API - Web APIs

Fetch API
=========

Fetch API 提供了一個能獲取包含跨網路資源在的資源介面。它有點像我們所熟悉的 `XMLHttpRequest` ，但這個新的 API 提供了更強更彈性的功能。概念與應用
-----

Fetch 提供了 `Request` (en-US) 與 `Response` 物件，還有其他牽涉網路請求的通用定義。這能讓他們在需要的時候被使用到，不管是 service worker、Cache API、還是其他處理或更動請求回應的相類事物、或是任何需要產生有序化產生回應的用例（use case）。

它也提供了諸如 CORS 與 HTTP origin 標頭語意的分散定義，能取代分散的定義。

要發動請求並取得資源的話，請使用 `GlobalFetch.fetch` (en-US) 方法。他實作了數種介面，並指定了 `Window` (en-US) 與 `WorkerGlobalScope` (en-US)，使它可以在任何想獲取資源的環境中使用。

`fetch()` 方法有一個強制性的參數，就是要取得資源的網址。該方法會回傳一個不論請求成敗，都會 resolve 的 promise `回應`。你也能選擇性地使用第二個稱為 `init` 的物件參數（請參見 `Request` (en-US)）。

當 `Response` 檢索後，在請求體裡面會定義一些請求體為何，還有要如何處理的方法（請參見 `Body`）。

你也可以直接用 `Request()` (en-US) 與 `Response()` (en-US) 建構子來建立請求與回應，不過你不太可能直接使用他，反而更可能是以其他 API 行動的結果為形式存在。（例如來自 service worker 的 `FetchEvent.respondWith` (en-US)）

**備註：** 你可以在使用 Fetch深入理解 Fetch，並在Fetch 的基本概念 (en-US)文章內理解概念。

### 中斷一次 Fetch

各家瀏覽器已經開始加入 `AbortController` 與 `AbortSignal` (en-US) 介面（也就是 Abort API）的實驗性支援，讓 Fetch 和 XHR 這類的操作在完成前可以被中斷。詳情請參閱相關介面的文件。

Fetch 介面
--------

`fetch()` (en-US)

用於取得資源的 `fetch()` 方法。

`Headers` (en-US)

代表請求/回應標頭，讓你能 query 並針對結果不同，採取不同行動。

`Request` (en-US)

代表資源請求。

`Response`

代表資源請求的回應。

Fetch mixin
-----------

`Body`

提供請求/回應訊息體的相關方法，能宣告內容的類別為何，以及該如何處理。

規範
--

| Specification |
| --- |
| Fetch Standard # fetch-method |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* 使用 Fetch
* ServiceWorker API (en-US)
* HTTP access control (CORS)
* HTTP
* Fetch polyfill
* Fetch 基本概念 (en-US)


PositionError - Web APIs

PositionError
=============

**`PositionError`** 介面表示使用定位設備時發生錯誤的原因。

屬性
--

*`PositionError` 介面沒有繼承任何屬性*。

`PositionError.code` Read only

回傳一個無符號整數（`unsigned short`）來表示錯誤碼。以下列出可能的值：

| 值 | 相對應的常數 | 描述 |
| --- | --- | --- |
| `1` | `PERMISSION_DENIED` | 取得地理資訊失敗，因為此頁面沒有獲取地理位置信息的權限。 |
| `2` | `POSITION_UNAVAILABLE` | 取得地理資訊失敗，因為至少有一個地理位置信息內的資訊回傳了錯誤。 |
| `3` | `TIMEOUT` | 取得地理資訊超過時限，利用`PositionOptions.timeout` 來定義取得地理資訊的時限。 |

`PositionError.message` Read only

回傳一個可讀的 `DOMString` 來描述錯誤的詳細訊息。注意規格中指出此訊息是用來除錯而非直接顯示在使用者介面。

方法
--

**`PositionError` 介面沒有實作也沒有繼承任何方法**。

規格
--

| Specification |
| --- |
| Geolocation API # position\_error\_interface |

瀏覽器的相容性
-------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

請參考
---

* Using geolocation (en-US)
* `Geolocation` 介面使用此物件。


Web Audio API - Web APIs

Web Audio API
=============

**實驗性質:** **這是一個實驗中的功能 (en-US)**
此功能在某些瀏覽器尚在開發中，請參考兼容表格以得到不同瀏覽器用的前輟。

**Web Audio API** 可於 Web App 或網頁上操作並播放音訊檔案。

Web Audio API 是根據模組化路由 (Modular routing) 的概念所設計。所謂的模組化路由，即是以「**音訊節點** **(Audio nodes)**」**執行基本的音訊作業**，節點又互相連接而構成「音訊路由圖 (Audio routing graphs)」。在同一環境 (Audio context) 內，又可支援數個音源與多樣的聲道配置。此模組化設計可提供更高的靈活度，並能建立複雜的音訊函式與動態效果。

音訊節點均透過其輸出與輸入而相互連結。各個輸入/輸出均具備數個**聲道** **(Channel)**，以構成特定的音訊配置。但目前已可支援單聲道、立體聲、四聲道、5.1 聲道等配置，並支援其他的離散配置。

音訊有多種來源。可能由特定的音訊節點 (如震盪器、自訂函式，甚或簡易的資料陣列) 直接在 JavaScript 中產生。音源除了可連至 HTML 媒體元素 (如 element is used to embed video content in an HTML or XHTML document.">`<video>` (en-US) 或 element is used to represents sound content in documents. Added as part of HTML5, it may contain several audio sources, represented using the src attribute or the <source> element; the browser will choose the most suitable one. Fallback c">`<audio>` (en-US))，亦可能來自於 WebRTC (en-US) 的 `MediaStream` (en-US) (本端裝置的相機或遠方電腦)。

特定音訊事件發生的時間點，均達到極高的精確度與極低的潛時，因此亦可用以詳細定義鼓類機器或音序器 (Sequencer) 所需的事件。

Web Audio API 亦可控制音訊的空間定位 (Spatialized) 作業：透過 source-listener 模型架構的系統，進而控制所要使用的左右相位 (Panning\*，*聲音放置於左右喇叭之間形成的立體音場中，以產生出空間感) 模*型\*，進而自動處理因距離遠近所產生的衰減，或是由於音源/聽者移動所發生的都卜勒移頻 (Doppler shift)。

參考
--

* `AnalyserNode` (en-US)
* `AudioBuffer` (en-US)
* `AudioBufferSourceNode` (en-US)
* `AudioContext` (en-US)
* `AudioDestinationNode` (en-US)
* `AudioListener` (en-US)
* `AudioNode` (en-US)
* `AudioParam` (en-US)
* `audioprocess` (en-US) (event)
* `AudioProcessingEvent` (en-US)
* `BiquadFilterNode` (en-US)
* `ChannelMergerNode` (en-US)
* `ChannelSplitterNode` (en-US)
* `complete` (en-US) (event)
* `ConvolverNode` (en-US)
* `DelayNode` (en-US)
* `DynamicsCompressorNode` (en-US)
* `ended` (en-US) (event)
* `GainNode`
* `MediaElementAudioSourceNode` (en-US)
* `MediaStreamAudioDestinationNode` (en-US)
* `MediaStreamAudioSourceNode` (en-US)
* `OfflineAudioCompletionEvent` (en-US)
* `OfflineAudioContext` (en-US)
* `OscillatorNode` (en-US)
* `PannerNode` (en-US)
* `ScriptProcessorNode` (en-US)
* `WaveShaperNode` (en-US)
線上教學
----

* 使用 Web Audio API
* Getting Started with the Web Audio API (僅說明 WebKit-only 的非標準建置)
* 混合定位音訊 (Positional Audio) 與 WebGL
* 以 Web Audio API 開發遊戲音訊
* 將 webkitAudioContext 程式碼移植為標準的 AudioContext (en-US)
規格
--

| Specification |
| --- |
| Web Audio API # AudioContext |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


PaymentRequest - Web APIs

PaymentRequest
==============

**Secure context:** This feature is available only in secure contexts (en-US) (HTTPS), in some or all supporting browsers.

**`PaymentRequest`** 介面是 Payment Request API 的主要切入點，它能讓網頁或 app 接受終端用戶的付款。

建構子
---

`PaymentRequest()` (en-US) Secure context

建立新的 `PaymentRequest` 物件。

屬性
--

`PaymentRequest.id` (en-US) Read only Secure context

個別 `PaymentRequest` 的唯一標識符（unique identifier），可透過 `details.id` 設定之。若尚未指定，預設為 UUID。

`PaymentRequest.shippingAddress` (en-US) Read only  Secure context

若透過付款設定（payment options）請求的話，回傳用戶指定的運送地址，以便計算運輸事宜。只有在呼叫的建構子 `requestShipping` flag 為 true 時，此屬性才能作動。另外，部份瀏覽器會出於隱私上的理由而只節錄部分地址，除非用戶表示交易手續即將完成（例如按下「付款」鈕）。

`PaymentRequest.shippingOption` (en-US) Read only  Secure context

回傳的運送選項的標識符。只有在呼叫的建構子 `requestShipping` flag 為 true 時，此屬性才能作動。

`PaymentRequest.shippingType` (en-US) Read only  Secure context

回傳用於完成交易的運送類型。可以是 `shipping`, `delivery`, `pickup`, 或在建構子未提供的情形下：`null`。

### 事件處理器

`PaymentRequest.onshippingaddresschange` (en-US) Secure context

用戶修改運送地址時觸發之。

`PaymentRequest.onshippingoptionchange` (en-US) Secure context

用戶修改運送選項時觸發之。

`PaymentRequest.onpaymentmethodchange` (en-US) Secure context

針對付款方法（如 Apple Pay），用戶修改支付方式時觸發之，比方說從信用卡改為簽帳卡。

`PaymentRequest.onmerchantvalidation` (en-US) Secure context

針對付款方法（如 Apple Pay），本事件會呼叫 `merchantvalidation` 事件，在用戶代理要求驗證付款商家或供應商是否合法時觸發之。

方法
--

`PaymentRequest.canMakePayment()` (en-US) Secure context

在呼叫 `show()` 前告訴 `PaymentRequest` 物件能不能付款。

`PaymentRequest.show()` (en-US) Secure context

讓用戶代理開始付款請求的用戶交互。

`PaymentRequest.abort()` (en-US) Secure context

讓用戶代理結束付款請求並刪除可能顯示的任何用戶界面。

規範
--

| Specification |
| --- |
| Payment Request API 1.1 # paymentrequest-interface |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


NodeList - Web APIs

NodeList
========

**`NodeList`** 物件是節點的集合，可藉由 `Node.childNodes` (en-US) 屬性以及 `document.querySelectorAll()` (en-US) 方法取得。

**備註：** 雖然 `NodeList` 不是 `Array`，但仍可以使用 `forEach()` 方法來進行迭代。一些老舊瀏覽器並未實作此方法。

在某些情況下，`NodeList` 為*動態集合（live collection）*，意思是 DOM 的改變會反映於集合。例如，`Node.childNodes` (en-US) 便是即時更新（live）的：

```js
var parent = document.getElementById("parent");
var child_nodes = parent.childNodes;
console.log(child_nodes.length); // let's assume "2"
parent.appendChild(document.createElement("div"));
console.log(child_nodes.length); // should output "3"
```

在其他的情況下，`NodeList` 是一個*靜態的集合（static collection）*，代表任何之後的 DOM 變化都不會影響集合的內容。`document.querySelectorAll()` (en-US) 會回傳一個靜態的 `NodeList`。

當你要選擇如何迭代 `NodeList` 中的項目時，最好能於心中區分動態與靜態集合，尤其是在取得集合長度（length of the list）的時候。

屬性
--

`NodeList.length` (en-US)

The number of nodes in the `NodeList`.

方法
--

`NodeList.item()` (en-US)

Returns an item in the list by its index, or `null` if the index is out-of-bounds; can be used as an alternative to simply accessing `nodeList[idx]` (which instead returns `undefined` when `idx` is out-of-bounds).

`NodeList.entries()` (en-US)

Returns an `iterator` allowing to go through all key/value pairs contained in this object.

`NodeList.forEach()` (en-US)

Executes a provided function once per `NodeList` element.

`NodeList.keys()` (en-US)

Returns an `iterator` allowing to go through all keys of the key/value pairs contained in this object.

`NodeList.values()` (en-US)

Returns an `iterator` allowing to go through all values of the key/value pairs contained in this object.

範例
--

It's possible to loop over the items in a `NodeList` using:

```js
for (var i = 0; i < myNodeList.length; ++i) {
  var item = myNodeList[i]; // Calling myNodeList.item(i) isn't necessary in JavaScript
}
```

Don't be tempted to use `for...in` (en-US) or `for each...in` to enumerate the items in the list, since that will also enumerate the length and item properties of the `NodeList` and cause errors if your script assumes it only has to deal with `element` (en-US) objects. Also, `for..in` is not guaranteed to visit the properties in any particular order.

`for...of` (en-US) loops will loop over `NodeList` objects correctly:

```js
var list = document.querySelectorAll("input[type=checkbox]");
for (var item of list) {
  item.checked = true;
}
```

Recent browsers also support iterator methods, `forEach()` (en-US), as well as `entries()` (en-US), `values()` (en-US), and `keys()` (en-US)

There is also an Internet Explorer compatible way to use `Array.prototype.forEach` (en-US) for iteration.

```js
var list = document.querySelectorAll("input[type=checkbox]");
Array.prototype.forEach.call(list, function (item) {
  item.checked = true;
});
```

NodeList 原型
-----------

You can also add prototypes to nodelist:

```js
var elements = document.querySelectorAll(".suggestions");

NodeList.prototype.addEventListener = function (event, func) {
  this.forEach(function (content, item) {
    content.addEventListener(event, func);
  });
};

function log() {
  console.log(this, " was clicked");
}

elements.addEventListener("click", log);
//or
elements.addEventListener("click", function () {
  console.log(this, " awas clicked");
});
// output from both will be element was clicked the element would be HTML Element
```

For information about forEach see Array.prototype.forEach() (en-US)

規範
--

| Specification |
| --- |
| DOM Standard # interface-nodelist |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Channel Messaging API - Web APIs

Channel Messaging API
=====================

Channel Messaging API 讓同屬一份文件不同瀏覽環境的兩份程式腳本 (如兩個 IFrame、或主頁面和 IFrame、文件和 `SharedWorker` (en-US)、或兩個 worker)，也能夠經由雙向 channel (通道) 兩端的 port (連接阜) 直接傳遞訊息互相溝通。

**備註：** 此功能可在 Web Worker (en-US) 中使用

Channel 訊息概念與使用情境
-----------------

`MessageChannel()` (en-US) 建構子產生 channel， 一但生成了，便可以存取 channel 兩端的 port: `MessageChannel.port1` (en-US) 和 `MessageChannel.port2` (en-US)，這兩個屬性會回傳 domxref("MessagePort")}} objects.)。建立 channel 的 app 使用 port1，另一端用 port2，利用 `window.postMessage` (en-US) 方法帶入參數，向 port2 傳送訊息以及移轉物件 (這裡也就是只 port)。

一但可移轉物件被移轉後，前任擁有者便失去所有權，例如當 port 移轉出去後，原本持有該 port 的環境便不能再使用之。目前可移轉物件只有 `ArrayBuffer` 以及 `MessagePort` (en-US)。

另一端的瀏覽環境則藉由 `MessagePort.onmessage` (en-US) 監聽訊息、從訊息事件物件的 data 屬性擷取訊息資料，然後再呼叫 `MessagePort.postMessage` (en-US) 回傳訊息。

如果想關閉訊息 channel，則呼叫 `MessagePort.close` (en-US)。

更多 API 使用細節請見 Using channel messaging (en-US)。

Channel 訊息介面
------------

`MessageChannel` (en-US)

生成一個新的 message channel。

`MessagePort` (en-US)

控制 port，用來傳送和監聽訊息。

`PortCollection`

`MessagePort`s 陣列，實驗性質方案；用來同時廣播到多個訊息 port。

範例
--

* Github 上有 channel messaging basic demo (run it live too)，一個簡單示範主頁和 `<iframe>` (en-US) 間的訊息溝通。
* 還有 multimessaging demo (run this live)，較為複雜的例子。
規範
--

| Specification |
| --- |
| HTML Standard # channel-messaging |

瀏覽器相容性
------

### api.MessageChannel

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.MessagePort

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

延伸閱讀
----

* Using channel messaging (en-US)
* Web Workers API (en-US)
* Broadcast Channel API (en-US)


DragEvent - Web APIs

DragEvent
=========

**`DragEvent`** 介面是一種 `DOM event`，定義了拖放操作時產生的事件物件。使用者藉由把指標裝置 (例如滑鼠) 放到有效區域並拖移到另一個新的位置 ( 如另外一個 DOM 元素 ) 來開始一個拖動的動作。 而應用程式可以自由地決定互動的方式來達到符合該應用程式的使用情境。

This interface inherits properties from `MouseEvent` (en-US) and `Event`.

屬性
--

`DragEvent.dataTransfer` Read only

The data that is transferred during a drag and drop interaction.

建構式
---

Although this interface has a constructor, it is not possible to create a useful DataTransfer object from script, since `DataTransfer` (en-US) objects have a processing and security model that is coordinated by the browser during drag-and-drops.

`DragEvent()` (en-US)

Creates a synthetic and untrusted DragEvent.

事件類型
----

`drag` (en-US)

在『被選擇的物件』被拖曳時觸發。

`dragend` (en-US)

在『被選擇的物件』結束拖曳時觸發 (就是放開滑鼠鍵、或按下 Esc 鍵時)。

`dragenter` (en-US)

當『被選擇的物件』被拖曳到『可以當目標的物件』時, 在『進入』該目標物件上方的瞬間觸發。注意, 不是『被選擇的物件』觸發此事件, 而是『可以當目標的物件』。

`dragleave` (en-US)

當『被選擇的物件』被拖曳到『可以當目標的物件』時, 在『離開』該目標物件上方的瞬間觸發。注意, 不是『被選擇的物件』觸發此事件, 而是『可以當目標的物件』。

`dragover` (en-US)

當『被選擇的物件』被拖曳到『可以當目標的物件』的上方時觸發 (頻率大約每秒數次)。注意, 不是『被選擇的物件』觸發此事件, 而是『可以當目標的物件』 。

`dragstart` (en-US)

在『被選擇的物件』開始拖曳時觸發。

`drop` (en-US)

當『被選擇的物件』被拖曳、放到『目標物件』時觸發。注意, 不是『被選擇的物件』觸發此事件, 而是『目標物件』。

通用事件處理器
-------

`GlobalEventHandlers.ondrag` (en-US)

A `global event handler` for the `drag` (en-US) event.

`GlobalEventHandlers.ondragend` (en-US)

A `global event handler` for the `dragend` (en-US) event.

`GlobalEventHandlers.ondragenter` (en-US)

A `global event handler` for the `dragenter` (en-US) event.

`GlobalEventHandlers.ondragleave` (en-US)

A `global event handler` for the `dragleave` (en-US) event.

`GlobalEventHandlers.ondragover` (en-US)

A `global event handler` for the `dragover` (en-US) event.

`GlobalEventHandlers.ondragstart` (en-US)

A `global event handler` for the `dragstart` (en-US) event.

`GlobalEventHandlers.ondrop` (en-US)

A `global event handler` for the `drop` (en-US) event.

範例
--

An Example of each property, constructor, event type and global event handlers is included in their respective reference page.

規範
--

| Specification |
| --- |
| HTML Standard # the-dragevent-interface |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* HTML 拖放 API
* 拖曳操作
* 推薦拖曳類型 (en-US)
* 拖拽和放置多個項目
* DataTransfer test - Paste or Drag


操控瀏覽器歷史紀錄 - Web APIs

操控瀏覽器歷史紀錄
=========

DOM `window` (en-US) 物件透過 `history` (en-US) 物件，提供了進入瀏覽歷史的方式。他透過一些方便的屬性與方法，讓你可以在歷史紀錄中往上一步或往下一步移動，並且讓你——從 HTML5 開始——能操作歷史紀錄堆疊（history stack）的內容。

在歷史紀錄中移動
--------

往前往後歷史紀錄可以用 `back()`, `forward()`, 和 `go()` 的方法。

### 往前往後

要在歷史紀錄中往上一步移動，可以：

```js
window.history.back();
```

這完全等同於用戶在瀏覽器上點選「上一頁」按鈕。

同樣的，你也可以往下一步移動（等同於用戶點擊往後一頁的按鈕）：

```js
window.history.forward();
```

### 移動到特定的歷史紀錄

你可以用 `go()` 方法來從頁面的 session history 紀錄中載入特定紀錄，以目前頁面的相對位置而定（目前的頁面想當然爾是 index 0）。

往前一頁（等同於呼叫 `back()`）：

```js
window.history.go(-1);
```

往後一頁（等同於呼叫 `forward()`）：

```js
window.history.go(1);
```

同樣的你也可以傳入 2，讓頁面直往後兩頁，依此類推。

你可以查看 length 這個屬性來取得目前瀏覽歷史的總數我：

```js
var numberOfEntries = window.history.length;
```

**備註：** Internet Explorer 支援在 `go()` 中以 URL 的值作為參數；這不在標準中，Gecko 也不支援。

加入和修改歷史紀錄
---------

HTML5 加入了 `history.pushState()` (en-US) 和 `history.replaceState()` 方法，讓你可以加入或修改歷史紀錄。這些方法都可以跟 `window.onpopstate` (en-US) 事件一同應用。

使用 `history.pushState()`後，會改變 `XMLHttpRequest` 時 HTTP 標頭中 referrer 的值。referrer 會是創造 `XMLHttpRequest` 物件時的當前視窗文件（`this`）的 URL。

### pushState() 方法範例

假設 `http://mozilla.org/foo.html` 執行了下面的 JavaScript：

```js
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
```

這會讓網址列顯示 `http://mozilla.org/bar.html`，但不會讓瀏覽器去載入 `bar.html`，甚或去檢查 `bar.html` 存在與否。

假設現在使用者瀏覽到 `http://google.com`，然後點擊上一頁鈕。這時網址列會顯示 `http://mozilla.org/bar.html`，頁面會獲得 `popstate` 的事件（*state object* 會包含一份 `stateObj` 的副件）。頁面長得跟 `foo.html` 很像，但是可能在 `popstate` 事件執行中被修改。

如果我再點一次上一頁鈕， 網址會改變成為 `http://mozilla.org/foo.html`，且文件會得到另外一個 `popstate` 事件，此次會包含一個 null state object。同樣的，回上頁鈕不會改變文件的內容，只是文件可能會在 `popstate` 事件中被手動更新。

### pushState() 方法

`pushState()` 取用三個參數：一個 state 物件、title（目前忽略）與 URL（可選用）。我們來看看三個參數的細節之處：

* **state object**——state object 是與 `pushState()` 建立的新瀏覽歷史紀錄有關的一個 JavaScript 物件。只要使用者到了新的 state ，一個 `popstate` 的事件就會被觸發，然後該事件的 `state` 屬性會包含一個複製的歷史紀錄的 state object。
 state 物件可以是任何可序列化的東西。因為 Firefox 儲存 state 物件到使用者的硬碟，當瀏覽器被重新啟動的時候，他們是可以被恢復的，因此我們加上了 640k 個字元的長度限制在一個以序列化表示的 state object。如果你傳送一個比這個更大的序列化表示的 state object 到 `pushState()`，這個方法會丟出一個例外事件。如果你需要更多空間的話，你可以試著用 `sessionStorage` 和／或 `localStorage`。
* **title**——Firefox 目前忽略了這個參數，雖然他以後有可能會採用。如果以後改變了這個作法，傳送空白的字串應該還會是安全的。另外，你可以傳送一個短的標題來敘述你想要到的 state。
* **URL**——這個新歷史紀錄的 URL 從這個參數做設定。值得注意的是，在 `pushState()` 被呼叫之後，瀏覽器並不會馬上嘗試載入這個 URL ，但是它可能在以後嘗試載入這個 URL ，例如使用者重新開啟瀏覽器之後。新的 URL 不一定需要為一個絕對的路徑；如果是相對路徑，會依據目前的 URL 來解析。新的 URL 需要與目前 URL 的 origin 是一樣的；否則，pushState() 會丟出一個錯誤的例外。這個參數是選擇性的；如果沒有被指定的話，他會設定為目前文件的 URL。

**備註：** 在 Gecko 2.0 到 Gecko 5.0，是採用 JSON 來序列化這個傳送的物件。從 Gecko 6.0 開始,這個物件是以 the structured clone algorithm 序列化。這會允許更多種不同的物件可以被安全的傳送。

從某種意義上，呼叫 `pushState()` 與設定 `window.location = "#foo"` 是類似的，兩個都會去建立和啟用另一個和目前文件有關的歷史紀錄。但是 `pushState()` 有一些優勢：

* 新的 URL 可以是任何一個與目前的 URL 在同一個 origin 的 URL。相對來說，只有你設定 `window.location` 只修改 hash 時，才讓你保持在同一個 `document` (en-US) 。
* 如果你不想要的話，你可以不必去改變 URL 。相對來說，設定 `window.location = "#foo";` 只有在目前的 hash 不是 `#foo` 的時候，會建立一個新的歷史紀錄。
* 你可以將任意的資料與你的新的歷史紀錄做關聯。用 hash-based 的方法，你需要將所有相關的資料編碼成一個短字串。
* If `title` is subsequently used by browsers, this data can be utilized (independent of, say, the hash).

注意 `pushState()` 永遠不會造成一個 `hashchange` 事件被觸發，即使新的 URL 和舊的 URL 的不同處只有 hash 的部份也不會。

In a XUL document, it creates the specified XUL element.

In other documents, it creates an element with a `null` namespace URI.

### replaceState() 方法

`history.replaceState()` 的執行就像 `history.pushState()` ，除了 `replaceState()` 是修改目前的歷史紀錄而不是創造一個新的。

`replaceState()` 很實用的時機是當你要更新目前歷史紀錄的 state object 或是 URL 來反應一些使用者的動作時。

**備註：** 在 Gecko 2.0 到 Gecko 5.0，是採用 JSON 來序列化這個傳送的物件。從 Gecko 6.0 開始, 這個物件是以 the structured clone algorithm 序列化。這會允許更多種不同的物件可以被安全的傳送。

### replaceState() 方法範例

Suppose `http://mozilla.org/foo.html` executes the following JavaScript:

```js
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
```

The explanation of these two lines above can be found at "Example of pushState() method" section. Then suppose `http://mozilla.org/bar.html` executes the following JavaScript:

```js
history.replaceState(stateObj, "page 3", "bar2.html");
```

This will cause the URL bar to display `http://mozilla.org/bar2.html`, but won't cause the browser to load `bar2.html` or even check that `bar2.html` exists.

Suppose now that the user now navigates to `http://www.microsoft.com`, then clicks back. At this point, the URL bar will display `http://mozilla.org/bar2.html`. If the user now clicks back again, the URL bar will display `http://mozilla.org/foo.html`, and totaly bypass bar.html.

### popstate 事件

每次 active 的歷史紀錄被更動的時候，一個 `popstate` 事件會被發送到目前的 window。如果被啟用的歷史紀錄是由於呼叫 `pushState` 建立的或是呼叫 `replaceState` 所影響的，這個 `popstate` 事件的 `state` 屬性會含有一個歷史紀錄的 state object 的副本。

使用範例參閱 `window.onpopstate` (en-US)。

### 讀取目前的 state

當你讀取頁面的時候，可能會有 non-null state 的物件。這會發生在，例如說，如果設定一個 state 物件（用 `pushState()` 或是 `replaceState()`），然後使用者重新啟動他的瀏覽器。當重新讀取你的頁面的時候，頁面會得到一個 `onload` 事件，但是沒有 `popstate` 事件。然而，如果你讀取了 `history.state` 屬性，你會得到像是 `popstate` 被觸發時，你會得到的 state object 。

像這樣使用 `history.state` 屬性，你可以讀取目前的歷史紀錄的`狀態`而不需要等待一個 `popstate` 事件：

```js
var currentState = history.state;
```

範例
--

完整的 AJAX 網站範例 ，請參閱：Ajax navigation example (en-US)。

規範
--

| Specification |
| --- |
| HTML Standard # the-history-interface |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


文件物件模型 (DOM) - Web APIs

文件物件模型 (DOM)
============

\*\*文件物件模型（*Document Object Model, DOM*）\*\*是 HTML、XML 和 SVG 文件的程式介面。它提供了一個文件（樹）的結構化表示法，並定義讓程式可以存取並改變文件架構、風格和內容的方法。DOM 提供了文件以擁有屬性與函式的節點與物件組成的結構化表示。節點也可以附加事件處理程序，一旦觸發事件就會執行處理程序。 本質上，它將網頁與腳本或程式語言連結在一起。

雖然常常使用 JavaScript 來存取 DOM，但它本身並不是 JavaScript 語言的一部分，而且它也可以被其他語言存取（雖然不太常見就是了）。

這裡有一篇 DOM 的介紹 (en-US)可供查閱。

DOM 介面
------

* `Attr` (en-US)
* `CharacterData` (en-US)
* `ChildNode`
實驗性質
* `Comment` (en-US)
* `CustomEvent`
* `Document` (en-US)
* `DocumentFragment`
* `DocumentType` (en-US)
* `DOMError` (en-US)
* `DOMException` (en-US)
* `DOMImplementation` (en-US)
* `DOMString`
* `DOMTimeStamp` (en-US)
* `DOMSettableTokenList`
* `DOMStringList` (en-US)
* `DOMTokenList`
* `Element` (en-US)
* `Event`
* `EventTarget`
* `HTMLCollection` (en-US)
* `MutationObserver`
* `MutationRecord` (en-US)
* `Node` (en-US)
* `NodeFilter` (en-US)
* `NodeIterator` (en-US)
* `NodeList`
* `ParentNode`
實驗性質
* `ProcessingInstruction` (en-US)
* `Range` (en-US)
* `Text` (en-US)
* `TreeWalker` (en-US)
* `URL` (en-US)
* `Window` (en-US)
* `Worker` (en-US)
* `XMLDocument` (en-US)
實驗性質
棄用的 DOM 介面
----------

文件物件模型正被大量的簡化。為了達成這個目的，下這些介面是在 DOM level 3 或更早的規範中就被刪掉了。由於不清楚是否會被再度納入，請姑且當他們已經被遺棄，並避免使用：

* `CDATASection` (en-US)
* `DOMConfiguration`
* `DOMErrorHandler`
* `DOMImplementationList`
* `DOMImplementationRegistry`
* `DOMImplementationSource`
* `DOMLocator`
* `DOMObject`
* `DOMUserData`
* `Entity`
* `EntityReference`
* `NamedNodeMap`
* `NameList`
* `Notation`
* `TypeInfo`
* `UserDataHandler`
*
HTML 介面
-------

一份包含 html 的文件會透過 `HTMLDocument` 介面來描述。注意 HTML 規範也擴展了 `Document` (en-US) 介面。

`HTMLDocument` 物件也提供了瀏覽器功能的存取：分頁、透過 `Window` (en-US) 介面描繪頁面的視窗、與其相關的 `樣式` （通常是 CSS ）、與本文關聯的瀏覽器 `歷史` (en-US)、以及一個文件內的 `選擇器` (en-US)。

### HTML 元素介面

* `HTMLAnchorElement` (en-US)
* `HTMLAppletElement`
* `HTMLAreaElement` (en-US)
* `HTMLAudioElement` (en-US)
* `HTMLBaseElement` (en-US)
* `HTMLBodyElement` (en-US)
* `HTMLBRElement` (en-US)
* `HTMLButtonElement` (en-US)
* `HTMLCanvasElement` (en-US)
* `HTMLDataElement` (en-US)
* `HTMLDataListElement` (en-US)
* `HTMLDialogElement` (en-US)
* `HTMLDirectoryElement`
* `HTMLDivElement` (en-US)
* `HTMLDListElement` (en-US)
* `HTMLElement` (en-US)
* `HTMLEmbedElement` (en-US)
* `HTMLFieldSetElement` (en-US)
* `HTMLFontElement` (en-US)
* `HTMLFormElement` (en-US)
* `HTMLFrameElement`
* `HTMLFrameSetElement` (en-US)
* `HTMLHeadElement` (en-US)
* `HTMLHeadingElement` (en-US)
* `HTMLHtmlElement` (en-US)
* `HTMLHRElement` (en-US)
* `HTMLIFrameElement` (en-US)
* `HTMLImageElement` (en-US)
* `HTMLInputElement` (en-US)
* `HTMLLabelElement` (en-US)
* `HTMLLegendElement` (en-US)
* `HTMLLIElement` (en-US)
* `HTMLLinkElement` (en-US)
* `HTMLMapElement` (en-US)
* `HTMLMediaElement` (en-US)
* `HTMLMenuElement` (en-US)
* `HTMLMetaElement` (en-US)
* `HTMLMeterElement` (en-US)
* `HTMLModElement` (en-US)
* `HTMLObjectElement` (en-US)
* `HTMLOListElement` (en-US)
* `HTMLOptGroupElement` (en-US)
* `HTMLOptionElement` (en-US)
* `HTMLOutputElement` (en-US)
* `HTMLParagraphElement` (en-US)
* `HTMLParamElement` (en-US)
* `HTMLPreElement` (en-US)
* `HTMLProgressElement` (en-US)
* `HTMLQuoteElement` (en-US)
* `HTMLScriptElement` (en-US)
* `HTMLSelectElement` (en-US)
* `HTMLSourceElement` (en-US)
* `HTMLSpanElement` (en-US)
* `HTMLStyleElement` (en-US)
* `HTMLTableElement` (en-US)
* `HTMLTableCaptionElement` (en-US)
* `HTMLTableCellElement` (en-US)
* `HTMLTableDataCellElement` (en-US)
* `HTMLTableHeaderCellElement` (en-US)
* `HTMLTableColElement` (en-US)
* `HTMLTableRowElement` (en-US)
* `HTMLTableSectionElement` (en-US)
* `HTMLTextAreaElement` (en-US)
* `HTMLTimeElement` (en-US)
* `HTMLTitleElement` (en-US)
* `HTMLTrackElement` (en-US)
* `HTMLUListElement` (en-US)
* `HTMLUnknownElement` (en-US)
* `HTMLVideoElement` (en-US)
### 其他介面

* `CanvasRenderingContext2D` (en-US)
* `CanvasGradient` (en-US)
* `CanvasPattern` (en-US)
* `TextMetrics` (en-US)
* `ImageData` (en-US)
* `CanvasPixelArray` (en-US)
* `NotifyAudioAvailableEvent`
* `HTMLAllCollection` (en-US)
* `HTMLFormControlsCollection` (en-US)
* `HTMLOptionsCollection` (en-US)
* `HTMLPropertiesCollection`
* `DOMStringMap` (en-US)
* `RadioNodeList` (en-US)
* `MediaError` (en-US)
### 棄用的 HTML 介面

* `HTMLIsIndexElement`
SVG 介面
------

### SVG 元素介面

* `SVGAElement` (en-US)
* `SVGAltGlyphElement`
* `SVGAltGlyphDefElement`
* `SVGAltGlyphItemElement`
* `SVGAnimationElement` (en-US)
* `SVGAnimateElement` (en-US)
* `SVGAnimateColorElement` (en-US)
* `SVGAnimateMotionElement` (en-US)
* `SVGAnimateTransformElement` (en-US)
* `SVGCircleElement` (en-US)
* `SVGClipPathElement` (en-US)
* `SVGColorProfileElement`
* `SVGComponentTransferFunctionElement` (en-US)
* `SVGCursorElement` (en-US)
* `SVGDefsElement` (en-US)
* `SVGDescElement` (en-US)
* `SVGElement` (en-US)
* `SVGEllipseElement` (en-US)
* `SVGFEBlendElement` (en-US)
* `SVGFEColorMatrixElement` (en-US)
* `SVGFEComponentTransferElement` (en-US)
* `SVGFECompositeElement` (en-US)
* `SVGFEConvolveMatrixElement` (en-US)
* `SVGFEDiffuseLightingElement` (en-US)
* `SVGFEDisplacementMapElement` (en-US)
* `SVGFEDistantLightElement` (en-US)
* `SVGFEFloodElement` (en-US)
* `SVGFEGaussianBlurElement` (en-US)
* `SVGFEImageElement` (en-US)
* `SVGFEMergeElement` (en-US)
* `SVGFEMergeNodeElement` (en-US)
* `SVGFEMorphologyElement` (en-US)
* `SVGFEOffsetElement` (en-US)
* `SVGFEPointLightElement` (en-US)
* `SVGFESpecularLightingElement` (en-US)
* `SVGFESpotLightElement` (en-US)
* `SVGFETileElement` (en-US)
* `SVGFETurbulenceElement` (en-US)
* `SVGFEFuncRElement` (en-US)
* `SVGFEFuncGElement` (en-US)
* `SVGFEFuncBElement` (en-US)
* `SVGFEFuncAElement` (en-US)
* `SVGFilterElement` (en-US)
* `SVGFilterPrimitiveStandardAttributes`
* `SVGFontElement` (en-US)
* `SVGFontFaceElement` (en-US)
* `SVGFontFaceFormatElement` (en-US)
* `SVGFontFaceNameElement` (en-US)
* `SVGFontFaceSrcElement` (en-US)
* `SVGFontFaceUriElement` (en-US)
* `SVGForeignObjectElement` (en-US)
* `SVGGElement` (en-US)
* `SVGGlyphElement` (en-US)
* `SVGGlyphRefElement` (en-US)
* `SVGGradientElement` (en-US)
* `SVGHKernElement` (en-US)
* `SVGImageElement` (en-US)
* `SVGLinearGradientElement` (en-US)
* `SVGLineElement` (en-US)
* `SVGMarkerElement` (en-US)
* `SVGMaskElement` (en-US)
* `SVGMetadataElement` (en-US)
* `SVGMissingGlyphElement` (en-US)
* `SVGMPathElement` (en-US)
* `SVGPathElement` (en-US)
* `SVGPatternElement` (en-US)
* `SVGPolylineElement` (en-US)
* `SVGPolygonElement` (en-US)
* `SVGRadialGradientElement` (en-US)
* `SVGRectElement` (en-US)
* `SVGScriptElement` (en-US)
* `SVGSetElement` (en-US)
* `SVGStopElement` (en-US)
* `SVGStyleElement` (en-US)
* `SVGSVGElement` (en-US)
* `SVGSwitchElement` (en-US)
* `SVGSymbolElement` (en-US)
* `SVGTextElement` (en-US)
* `SVGTextPathElement` (en-US)
* `SVGTitleElement` (en-US)
* `SVGTRefElement` (en-US)
* `SVGTSpanElement` (en-US)
* `SVGUseElement` (en-US)
* `SVGViewElement` (en-US)
* `SVGVKernElement` (en-US)
### SVG 資料型別介面

這裡是資料型態的 DOM API，在 SVG 特性和性質的定義中被使用。

**備註：** 從 Gecko 5.0 開始，下列 SVG 相關的 DOM 介面物件的表示清單，現在可以被索引且可以像陣列般被取用；此外，他們也有 length 屬性來標示其清單中的項目個數：`SVGLengthList` (en-US)、`SVGNumberList` (en-US)、`SVGPathSegList`，和 `SVGPointList` (en-US)。

#### 靜態類型

* `SVGAngle` (en-US)
* `SVGColor`
* `SVGICCColor`
* `SVGElementInstance`
* `SVGElementInstanceList`
* `SVGLength` (en-US)
* `SVGLengthList` (en-US)
* `SVGMatrix` (en-US)
* `SVGNumber` (en-US)
* `SVGNumberList` (en-US)
* `SVGPaint`
* `SVGPoint` (en-US)
* `SVGPointList` (en-US)
* `SVGPreserveAspectRatio` (en-US)
* `SVGRect` (en-US)
* `SVGStringList` (en-US)
* `SVGTransform` (en-US)
* `SVGTransformList` (en-US)

#### 動畫類型

* `SVGAnimatedAngle` (en-US)
* `SVGAnimatedBoolean` (en-US)
* `SVGAnimatedEnumeration` (en-US)
* `SVGAnimatedInteger` (en-US)
* `SVGAnimatedLength` (en-US)
* `SVGAnimatedLengthList` (en-US)
* `SVGAnimatedNumber` (en-US)
* `SVGAnimatedNumberList` (en-US)
* `SVGAnimatedPreserveAspectRatio` (en-US)
* `SVGAnimatedRect` (en-US)
* `SVGAnimatedString` (en-US)
* `SVGAnimatedTransformList` (en-US)
### SMIL 相關介面

* `ElementTimeControl`
* `TimeEvent` (en-US)
### 其他的 SVG 介面

* `SVGAnimatedPathData`
* `SVGAnimatedPoints` (en-US)
* `SVGColorProfileRule`
* `SVGCSSRule`
* `SVGExternalResourcesRequired`
* `SVGFitToViewBox`
* `SVGLangSpace`
* `SVGLocatable`
* `SVGRenderingIntent` (en-US)
* `SVGStylable` (en-US)
* `SVGTests`
* `SVGTextContentElement` (en-US)
* `SVGTextPositioningElement` (en-US)
* `SVGTransformable`
* `SVGUnitTypes` (en-US)
* `SVGURIReference` (en-US)
* `SVGViewSpec`
* `SVGZoomAndPan`
相關連結
----

* DOM 範例 (en-US)


Storage - Web APIs

Storage
=======

Web Storage API (en-US) 中的 **`Storage`** 介面提供了存取特定 domain session 及本機儲存的方法。舉例而言，它能夠對存取的資料進行新增、刪除、修改，

在操作上，如果是對象是 domain session storage ，會呼叫 `Window.sessionStorage` 。而若是 local storage，則呼叫 `Window.localStorage` 。

屬性
--

`Storage.length` (en-US) Read only

返回一數字，代表儲存在 `Storage` 中的物件的數量。

方法
--

`Storage.key()` (en-US)

當傳入一數字 `n`, 會返回 storage 裡第 n 個值的 key 值。

`Storage.getItem()` (en-US)

當傳入一 key 值, 會返回 storage 裡此 key 值對應的 value 。

`Storage.setItem()` (en-US)

當傳入 key 及 value 的值, 會在 storage 裡新增此 key 及 value 值，若 key 已存在，則會把值更新成傳入的 value。

`Storage.removeItem()` (en-US)

當傳入一 key 值, 會把此 key 從 storage 裡刪除。

`Storage.clear()` (en-US)

執行此方法，會刪除所有在 storage 裡的 key。

範例
--

在這裡，我們藉由呼叫 `localStorage` 來存取 `Storage` 物件，首先使用 `!localStorage.getItem('bgcolor')` 來確認 storage 裡是否有項目存在。

如果有，則執行函示 `setStyles()` ，這個函示使用 `Storage.getItem()` (en-US) 取得 storage 的值，並且用這些值更新頁面樣式 。

如果沒有，便執行另一個函示 `populateStorage()`，他使用 `Storage.setItem()` (en-US) 先設定 storage 項目的值，然後才執行`setStyles()`。

```js
if (!localStorage.getItem("bgcolor")) {
  populateStorage();
}
setStyles();

function populateStorage() {
  localStorage.setItem("bgcolor", document.getElementById("bgcolor").value);
  localStorage.setItem("font", document.getElementById("font").value);
  localStorage.setItem("image", document.getElementById("image").value);
}

function setStyles() {
  var currentColor = localStorage.getItem("bgcolor");
  var currentFont = localStorage.getItem("font");
  var currentImage = localStorage.getItem("image");

  document.getElementById("bgcolor").value = currentColor;
  document.getElementById("font").value = currentFont;
  document.getElementById("image").value = currentImage;

  htmlElem.style.backgroundColor = "#" + currentColor;
  pElem.style.fontFamily = currentFont;
  imgElem.setAttribute("src", currentImage);
}
```

**備註：** 想要看這個範例完整運行，可以參考我們的 Web Storage Demo.

規範
--

| Specification |
| --- |
| HTML Standard # storage |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using the Web Storage API (en-US)
* `Window.localStorage`
* `Window.sessionStorage`
* `CacheStorage` (en-US)


FileList - Web APIs

FileList
========

`FileList` 型別物件通常來自 HTML `<input>` (en-US) 元素 `DOM` 物件的 `files` 屬性（property）。你可以操作 `FileList` 物件來存取使用者透過 `<input type="file">` 元素所選取的檔案，或由拖放操作所產生的檔案（請參考 `DataTransfer` (en-US) 物件的更多使用細節）。

**備註：** 在 Gecko 1.9.2 之前，`<input>` (en-US) 元素只支援一次選取一個檔案，這代表了 `FileList` 只能夠包含一個 `File` 物件。從 Gecko 1.9.2 開始，假如 `<input>` 元素的 `multiple` 屬性（attribute）為 true，則 FileList 就可能會包含多個檔案。

使用 FileList
-----------

所有 `<input>` 元素節點的 `DOM` 物件都擁有 `files` 屬性（property），此屬性即為 `FileList`，是一個可藉此存取使用者選取之檔案的類陣列物件。以下範例展示了一個 `type` 屬性（attribute）值為 `file` 的 HTML `<input>` 元素：

```html
<input id="fileItem" type="file" />
```

下面範例演示了如何取得 `<input>` 元素節點中所包含的第一個 `File` 型別物件：

```js
var file = document.getElementById("fileItem").files[0];
```

方法概觀
----

| `File item(index);` |
| --- |

屬性
--

| 屬性名稱 | 型別 | 描述 |
| --- | --- | --- |
| `length` | `integer` | 表示 `FileList` 物件中的檔案數量，唯讀。 |

方法
--

### item()

回傳 `FileList` 中指定索引的 `File` 物件。

```js
File item(
  index
);
```

#### 參數

`index`

要取得的檔案之索引（起始於零）。

#### 回傳值

要求的 `File` 物件。

範例
--

此範例演示了迭代所有之使用者於 `<input>` 元素選取的檔案：

```js
// fileInput is an HTML input element: <input type="file" id="myfileinput" multiple>
var fileInput = document.getElementById("myfileinput");

// files is a FileList object (similar to NodeList)
var files = fileInput.files;
var file;

// loop through files
for (var i = 0; i < files.length; i++) {
  // get item
  file = files.item(i);
  //or
  file = files[i];

  alert(file.name);
}
```

以下是更完整的範例：

```html
<!doctype html>
<html>
  <head> </head>
  <body>
    <!--multiple is set to allow multiple files to be selected-->

    <input id="myfiles" multiple type="file" />
  </body>

  <script>
 var pullfiles = function () {
 // love the query selector
 var fileInput = document.querySelector("#myfiles");
 var files = fileInput.files;
 // cache files.length
 var fl = files.length;
 var i = 0;

 while (i < fl) {
 // localize file var in the loop
 var file = files[i];
 alert(file.name);
 i++;
 }
 };

 // set the input element onchange to call pullfiles
 document.querySelector("#myfiles").onchange = pullfiles;

 //a.t
 </script>
</html>
```

規範
--

* File upload state (HTML5 working draft)
參見
--

* 在網頁應用程式中使用本地檔案
* `File`
* `FileReader`


KeyboardEvent - Web APIs

KeyboardEvent
=============

**`KeyboardEvent`** objects 用來詳述使用者和網頁之間，經由鍵盤產生的互動。每個事件（`event`）都記錄著一次鍵盤動作。事件類型（`keydown` 、 `keypress` 和 `keyup`）用來表示鍵盤執行哪種動作。

**備註：** `KeyboardEvent` 僅顯示在鍵盤上發生的事。當你需要進行文字輸入的操作，請使用 HTML5 `input` (en-US) event 代替 `KeyboardEvent` 。舉例來說，當使用者在手寫系統，例如平板電腦，輸入文字時，並不會啟動 key events 。

建構子
---

`KeyboardEvent()`

建立一 `KeyboardEvent` 物件。

方法
--

*本介面（interface）亦繼承其父 `UIEvent` 和 `Event` 的方法。*

`KeyboardEvent.getModifierState()` (en-US)

回傳一 `Boolean`。用來表示當事件建立時，修飾鍵（例如 `Alt`、 `Shift`、 `Ctrl`、或是 `Meta`） 是否是按下的。

`KeyboardEvent.initKeyEvent()` (en-US)
已棄用

初始化一個 `KeyboardEvent` object。這個 method 只有 Gecko 有在使用（其他瀏覽器是使用 `KeyboardEvent.initKeyboardEvent()` (en-US)），並且不應該再繼續使用。現代的標準規範是使用 `KeyboardEvent()` constructor。

`KeyboardEvent.initKeyboardEvent()` (en-US)
已棄用

初始化一個 `KeyboardEvent` object。 Gecko 從未實作過該 method （Gecko 是使用 `KeyboardEvent.initKeyEvent()` (en-US)) ，並且不應該再繼續使用。現代的標準規範是使用 `KeyboardEvent()` constructor。

Properties
----------

*本介面（ interface）亦繼承其父，`UIEvent` 和 `Event` ，的 properties 。*

`KeyboardEvent.altKey` (en-US) Read only

一個 `Boolean` 。用來表示在事件建立時， `Alt` （OS X 中是 `Option` 或 `⌥` ） 鍵是否執行中。

`KeyboardEvent.char`
非標準

已棄用
Read only

一個 `DOMString` ，返回鍵盤對應的字符。若是該鍵對應一個實際的字符，則其值為對應該字符的一個非空的 Unicode 字串；若沒對應的話，則返回一個空字串。

**備註：** If the key is used as a macro that inserts multiple characters, this attribute's value is the entire string, not just the first character.

**警告：** 在 DOM Level 3 Events ，該 propertie 已被移除。現在只有 IE9+ 支持它。

`KeyboardEvent.charCode` (en-US)
已棄用
Read only

Returns a `Number` representing the Unicode reference number of the key; this attribute is used only by the `keypress` event. For keys whose `char` attribute contains multiple characters, this is the Unicode value of the first character in that attribute. In Firefox 26 this returns codes for printable characters.

**警告：** 此 attribute 已被淘汰。如果可以，建議使用 `KeyboardEvent.key` (en-US)。

`KeyboardEvent.code` (en-US) Read only

一個 `DOMString` 。返回事件對應的按鍵的代碼。

`KeyboardEvent.ctrlKey` (en-US) Read only

一個 `Boolean` 。用來表示在事件建立時， `Ctrl` 鍵是否執行中。

`KeyboardEvent.isComposing` (en-US) Read only

一個 `Boolean` 。用來表示其觸發時間是否在 `compositionstart` 和 `compositionend` 之間。

`KeyboardEvent.key` (en-US) Read only

一個 `DOMString` ，用來事件對應的按鍵的值（key value）。

`KeyboardEvent.keyCode` (en-US)
已棄用
Read only

Returns a `Number` representing a system and implementation dependent numerical code identifying the unmodified value of the pressed key.

**警告：** 此 attribute 已被淘汰。如果可以，建議使用`KeyboardEvent.key` (en-US)。

`KeyboardEvent.locale` Read only

Returns a `DOMString` representing a locale string indicating the locale the keyboard is configured for. This may be the empty string if the browser or device doesn't know the keyboard's locale.

**備註：** This does not describe the locale of the data being entered. A user may be using one keyboard layout while typing text in a different language.

`KeyboardEvent.location` (en-US) Read only

Returns a `Number` representing the location of the key on the keyboard or other input device.

`KeyboardEvent.metaKey` (en-US) Read only

Returns a `Boolean` that is `true` if the `Meta` (on Mac keyboards, the `⌘ Command` key; on Windows keyboards, the Windows key (`⊞`)) key was active when the key event was generated.

`KeyboardEvent.repeat` (en-US) Read only

Returns a `Boolean` that is `true` if the key is being held down such that it is automatically repeating.

`KeyboardEvent.shiftKey` (en-US) Read only

Returns a `Boolean` that is `true` if the `Shift` key was active when the key event was generated.

`KeyboardEvent.which` (en-US)
已棄用
Read only

Returns a `Number` representing a system and implementation dependent numeric code identifying the unmodified value of the pressed key; this is usually the same as `keyCode`.

**警告：** 此 attribute 已被淘汰。如果可以，建議使用 `KeyboardEvent.key` (en-US)。

注意
--

KeyboardEvent 有 `keydown`、`keypress`、`keyup` 三種事件。對大多數的按鍵而言，Gecko 觸發事件的順序如下：

1. 當按鍵按下時，會送出 `keydown` event。
2. 當按鍵不是特殊鍵（modifier key），例如 `Ctrl`、`Alt`……等等，會送出 `keypress` event。
3. 當按鍵放開時，會送出 `keyup` event。
### 特殊狀況

某些按鍵，例如 `Caps Lock`、`Num Lock` 和 `Scroll Lock` 能切換鍵盤上的 LED 燈。在 Windows 和 Linux 系統上，這些按鍵只會觸發 `keydown` 和 `keyup` 事件。但是 Linux 上的 Firefox 12 或更早的版本亦會觸發 `keypress` 事件。

而在 Mac 電腦則不同，`Caps Lock` 只會觸發 `keydown` 事件；而 `Num Lock` 則是只有舊版的 Mac 電腦（2007 或之前的版本）才有，現在的 Mac 即便使用外部鍵盤也不支援 `Num Lock`。雖說舊版的 Mac 電腦支援 `Num Lock` 鍵，但 `Num Lock` 並不會執行任何 KeyboardEvent；而 Gecko 瀏覽器在特殊情況（外接一個有 `F14` 的鍵盤）下能支援 `Scroll Lock`，但是它會產生 `keypress` 事件。這個異常狀態是個 bug，詳情可參考 Firefox bug 602812。

### 自動迴圈（Auto-Repeat）的執行

當按鍵按下去不放時，它會開始一個自動迴圈。並導致觸發一系列的相似事件，如下所示：

1. `keydown`
2. `keypress`
3. `keydown`
4. `keypress`
5. （不斷重複，直到使用者放開按鍵）
6. `keyup`

在 DOM Level 3 說明書有提及這問題是會發生的。其中所存在的問題如下說明：

#### 部分 GTK 環境，例如 Ubuntu 9.4，的自動迴圈

部分的 GTK-based 環境之中，自動迴圈在發生的過程中會自動觸發電腦本機的 key-up 事件。然而，對 Gecko 而言，並沒有方法可以分辨使用者重複點擊按鍵與自動迴圈（按鍵按住不放）的差異。在這類的環境下，按鍵按住不放會重複執行下列事件：

1. `keydown`
2. `keypress`
3. `keyup`
4. `keydown`
5. `keypress`
6. `keyup`
7. （不斷重複，直到使用者放開按鍵）
8. `keyup`

不幸地，在這些環境之下，web content 亦沒有方法告訴使用者重複點擊按鍵與自動迴圈的差異。

#### Gecko 5.0 以前的自動迴圈

Gecko 5.0 以前，在不同平台上，鍵盤的處理與現在相比較不統一。

Windows

自動迴圈的結果與 Gecko 4.0 或更新的版本類似

Mac

在第一個 keydown 執行後，僅執行 keypress 事件，一直到案件放開（即送出 keyup 事件指令），過程中不會送出任何 keydown 事件。

Linux

鍵盤事件的執行根據平台不同而有所不同。它有可能表現得像是 Windows 也有可能像 Mac ，這取決於本地的事件模型（native event model）是如何執行的。

範例
--

```js
<!DOCTYPE html>
<html>
<head>
<script>
var metaChar = false;
var exampleKey = 16;

function keyEvent(event) {
  var key = event.keyCode || event.which;
  var keychar = String.fromCharCode(key);
  if (key == exampleKey) {
    metaChar = true;
  }
  if (key != exampleKey) {
    if (metaChar) {
      alert("Combination of metaKey + " + keychar);
      metaChar = false;
    } else {
      alert("Key pressed " + key);
    }
  }
}

function metaKeyUp (event) {
  var key = event.keyCode || event.which;

  if (key == exampleKey) {
    metaChar = false;
  }
}
</script>
</head>

<body onkeydown="keyEvent(event)" onkeyup="metaKeyUp(event)">
</body>
</html>
```

規格
--

| Specification |
| --- |
| UI Events # interface-keyboardevent |

The `KeyboardEvent` interface specification went through numerous draft versions, first under DOM Events Level 2 where it was dropped as no consensus arose, then under DOM Events Level 3. This led to the implementation of non-standard initialization methods, the early DOM Events Level 2 version, `KeyboardEvent.initKeyEvent()` (en-US) by Gecko browsers and the early DOM Events Level 3 version, `KeyboardEvent.initKeyboardEvent()` (en-US) by others. Both have been superseded by the modern usage of a constructor: `KeyboardEvent()`.

瀏覽器支援度
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

More compatibility data is available on other pages:

* `.code` ：請參考《瀏覽器支援度》的 `KeyboardEvent.code` (en-US) 部分。
* `.key`：請參考《瀏覽器支援度》的 `KeyboardEvent.key` (en-US) 部分。
* `.getModifierState()` ：請參考《瀏覽器支援度》的 `KeyboardEvent.getModifierState` (en-US) 部分。


MutationObserver - Web APIs

MutationObserver
================

`MutationObserver` 提供開發人員一個方法，來對 DOM tree 的變動來作反應，這被設計用來替換在 DOM3 事件規範中的 Mutation Events。

建構式
---

### `MutationObserver()`

以下舉例為一個新的 DOM mutation observers 建構式。
```

new MutationObserver(
  function callback
);
```

#### 參數

`callback`

這個函式會在 DOM 有變化時被呼叫，observer 會用兩個參數來呼叫它，第一個是 `MutationRecord` 物件陣列，而第二個參數則是觀察者目標本身。

Instance methods
----------------

| `void observe( `Node` (en-US) target, MutationObserverInit options );` |
| --- |
| `void disconnect();` |
| `Array takeRecords();` |

**備註：** `Node` (en-US) target should not be confused with NodeJS.

### `observe()`

Registers the `MutationObserver` instance to receive notifications of DOM mutations on the specified node.
```

void observe(
  `Node` (en-US) target,
  MutationObserverInit options
);
```

#### Parameters

`target`

The `Node` (en-US) on which to observe DOM mutations.

`options`

A `MutationObserverInit` object, specifies which DOM mutations should be reported.

**備註：** Adding an observer to an element is just like addEventListener, if you observe the element multiple times it does not make a difference. Meaning if you observe element twice, the observe callback does not fire twice, nor will you have to run disconnect() twice. In other words, once an element is observed, observing it again with the same observer instance will do nothing. However if the callback object is different it will of course add another observer to it.

### `disconnect()`

Stops the `MutationObserver` instance from receiving notifications of DOM mutations. Until the `observe()` method is used again, observer's callback will not be invoked.
```

void disconnect();
```

### `takeRecords()`

Empties the `MutationObserver` instance's record queue and returns what was in there.
```

Array takeRecords();
```

#### Return value

Returns an Array of `MutationRecord`s.

`MutationObserverInit`
----------------------

`MutationObserverInit` is an object which can specify the following properties:

**備註：** At the very least, `childList`, `attributes`, or `characterData` must be set to `true`. Otherwise, "An invalid or illegal string was specified" error is thrown.

| Property | Description |
| --- | --- |
| `childList` | Set to `true` if additions and removals of the target node's child elements (including text nodes) are to be observed. |
| `attributes` | Set to `true` if mutations to target's attributes are to be observed. |
| `characterData` | Set to `true` if mutations to target's data are to be observed. |
| `subtree` | Set to `true` if mutations to not just target, but also target's descendants are to be observed. |
| `attributeOldValue` | Set to `true` if `attributes` is set to `true` and target's attribute value before the mutation needs to be recorded. |
| `characterDataOldValue` | Set to `true` if `characterData` is set to `true` and target's data before the mutation needs to be recorded. |
| `attributeFilter` | Set to an array of attribute local names (without namespace) if not all attribute mutations need to be observed. |

`MutationRecord`
----------------

`MutationRecord` is the object that will be passed to the observer's callback. It has the following properties:

| Property | Type | Description |
| --- | --- | --- |
| `type` | `String` | Returns `attributes` if the mutation was an attribute mutation, `characterData` if it was a mutation to a `CharacterData` node, and `childList` if it was a mutation to the tree of nodes. |
| `target` | `Node` (en-US) | Returns the node the mutation affected, depending on the `type`. For `attributes`, it is the element whose attribute changed. For `characterData`, it is the `CharacterData` node. For `childList`, it is the node whose children changed. |
| `addedNodes` | `NodeList` | Return the nodes added. Will be an empty `NodeList` if no nodes were added. |
| `removedNodes` | `NodeList` | Return the nodes removed. Will be an empty `NodeList` if no nodes were removed. |
| `previousSibling` | `Node` (en-US) | Return the previous sibling of the added or removed nodes, or `null`. |
| `nextSibling` | `Node` (en-US) | Return the next sibling of the added or removed nodes, or `null`. |
| `attributeName` | `String` | Returns the local name of the changed attribute, or `null`. |
| `attributeNamespace` | `String` | Returns the namespace of the changed attribute, or `null`. |
| `oldValue` | `String` | The return value depends on the `type`. For `attributes`, it is the value of the changed attribute before the change. For `characterData`, it is the data of the changed node before the change. For `childList`, it is `null`. |

Example usage
-------------

The following example was taken from this blog post.

```js
// select the target node
var target = document.querySelector("#some-id");

// create an observer instance
var observer = new MutationObserver(function (mutations) {
  mutations.forEach(function (mutation) {
    console.log(mutation.type);
  });
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();
```

Additional reading
------------------

* A brief overview
* A more in-depth discussion
* A screencast by Chromium developer Rafael Weinstein
* The mutation summary library
* The DOM standard which defines the `MutationObserver` interface
Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


HTMLDocument - Web APIs

HTMLDocument
============

**`HTMLDocument`** 是一個關於 `DOM` 的抽象介面，提供了 `Document` (en-US) 定義之外的 XML 文件屬性及方法，以用來操作 HTML。

`window.document` 為 `HTMLDocument` 的物件實體，`HTMLDocument` 所有屬性與方法的說明已包含在 `Document` 頁面。由於現在的 `HTMLDocument` 是透過了綁定轉型（binding-specific casting）的方式來運作，所以 `HTMLDocument` 已不再是繼承 `Document`。

規範
--

* http://www.w3.org/TR/DOM-Level-2-HTM...ml#ID-26809268


Position - Web APIs

Position
========

**`Position`** 介面表示在給定時間相關裝置的位置。這個位置用一個 `Coordinates` 物件表示，包括裝置在地球上的二維位置，以及裝置的海拔高度和速度。

屬性
--

*`Position` 介面沒有繼承任何屬性*

`Position.coords` Read only

回傳一個定義當前位置的 `Coordinates` 物件。

`Position.timestamp` Read only

回傳一個時間戳 `DOMTimeStamp` (en-US) ，這個時間戳表示獲取到位置的時間。

方法
--

**`Position 介面沒有實作或繼承任何方法`**

規格
--

| Specification |
| --- |
| Geolocation API # position\_interface |

瀏覽器的相容性
-------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

請參考
---

* Using geolocation (en-US)
* `Geolocation` 介面使用此物件。


Canvas API - Web APIs

Canvas API
==========

**`<canvas>`** 是 HTML5 的新元素，可透過 Script（通常是 JavaScript）繪製圖形。例如，可以用來繪圖、合成圖照片、建立動畫、甚至處理即時的影片播放。

Mozilla 應用程式從 Gecko 1.8（也就是 Firefox 1.5）起開始支援 `<canvas>`。這個元素最初由蘋果 OS X Dashboard 和 Safari 引入。Internet Explorer 9 以上版本也有支援 `<canvas>`，但較舊的 IE 版本則須嵌入 Google Explorer Canvas 專案中的程式腳本，才能得到有效的支援。Opera 9 也支援 `<canvas>`。

`<canvas>` 元素通常也被 WebGL (en-US) 用來在網頁上顯示使用硬體加速繪製的 3D 圖形。

範例
--

這則簡單的範例使用了`CanvasRenderingContext2D.fillRect()` (en-US)這個方法。

### HTML

```html
<canvas id="canvas"></canvas>
```

### JavaScript

```js
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);
```

Edit the code below and see your changes update live in the canvas:
```

<canvas id="canvas" width="400" height="200" class="playable-canvas"></canvas>
<div class="playable-buttons">
  <input id="edit" type="button" value="Edit" />
  <input id="reset" type="button" value="Reset" />
</div>
<textarea id="code" class="playable-code">
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);</textarea
>
```

```
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var textarea = document.getElementById("code");
var reset = document.getElementById("reset");
var edit = document.getElementById("edit");
var code = textarea.value;

function drawCanvas() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  eval(textarea.value);
}

reset.addEventListener("click", function () {
  textarea.value = code;
  drawCanvas();
});

edit.addEventListener("click", function () {
  textarea.focus();
});

textarea.addEventListener("input", drawCanvas);
window.addEventListener("load", drawCanvas);
```

參考
--

* `HTMLCanvasElement` (en-US)
* `CanvasRenderingContext2D` (en-US)
* `CanvasGradient` (en-US)
* `CanvasPattern` (en-US)
* `ImageBitmap` (en-US)
* `ImageData` (en-US)
* `TextMetrics` (en-US)
* `Path2D` (en-US)
實驗性質

這些與`WebGLRenderingContext`有關的標識，皆引用在WebGL (en-US)

教程指南
----

Canvas tutorial

這個全部的課程包含 `<canvas>` 基礎的使用和高階的應用。

Code snippets: Canvas

一些延伸的開發功能，包含`<canvas>`。

Demo: A basic ray-caster

使用`<canvas>`做的光線追蹤(ray-tracing )範例。

Drawing DOM objects into a canvas

如何在 DOM`<canvas>`之中，畫個物件。例如 HTML 的元素。

Manipulating video using canvas (en-US)

結合`<video>` (en-US) 和 `<canvas>` 去控制影像資料的真實時間

資源
--

### Generic

* HTML5 Canvas Deep Dive
* Canvas Handbook
### Libraries

* Fabric.js is an open-source canvas library with SVG parsing capabilities.
* Kinetic.js is an open-source canvas library focused on interactivity for desktop and mobile applications.
* Paper.js is an open source vector graphics scripting framework that runs on top of the HTML5 Canvas.
* Origami.js is an open source lightweight canvas library.
* libCanvas 是一個強大且輕量化的 canvas 框架。
* Processing.js 是視覺化程式語言 Processing 的移植版。
* PlayCanvas is an open source game engine.
* Pixi.js is an open source game engine.
* PlotKit 是一個製作圖表和圖形的函式庫。
* Rekapi 是一個用來控制動畫影格的 Canvas API。
* PhiloGL 是一個可應用在資料視覺化、遊戲開發的 WebGL 框架。
* JavaScript InfoVis Toolkit 可在網頁上建立 2D 的互動式 Canvas 視覺化資料。
* EaselJS 是一個自由 / 開放源始碼的函式庫，目的在簡化 canvas 於遊戲與美術的開發難度，類似 Flash API。
* Scrawl-canvas is another open-source javascript library for creating and manipulating 2d canvas elements
規範
--

| Specification |
| --- |
| HTML Standard # the-canvas-element |

參見
--

* WebGL (en-US)


DOMParser - Web APIs

DOMParser
=========

**實驗性質:** **這是一個實驗中的功能 (en-US)**
此功能在某些瀏覽器尚在開發中，請參考兼容表格以得到不同瀏覽器用的前輟。

`DOMParser可以將XML或是HTML格式的字串轉成`DOM 文件 (en-US). `DOMParser`的規格請參閱DOM 解譯與串流化.

請注意XMLHttpRequest解譯的是 URL 連結內容裡的 XML 與 HTML 文件.

產生一個 DOMParser
--------------

" `new DOMParser()" 可產生DOMParser`.

`關於如何在Firefox外掛程式中產生DOMParser,`請參考`nsIDOMParser文件`

解譯 XML
------

產生解譯物件後，請呼叫`parseFromString方法函式來將XML字串轉換成DOM物件`:

```js
var parser = new DOMParser();
var doc = parser.parseFromString(stringContainingXMLSource, "application/xml");
```

### 錯誤處理

請注意如果解譯過程出錯,目前的 `DOMParser` 不會丟出異常物件（exception），但是會回傳一個錯誤文件（請看 Firefox bug 45566）：

```xml
<parsererror xmlns="http://www.mozilla.org/newlayout/xml/parsererror.xml">
(error description)
<sourcetext>(a snippet of the source XML)</sourcetext>
</parsererror>
```

解譯錯誤也會記錄在錯誤終端機中（Error Console）, 紀錄裡頭的文件 URI (如下) 則為錯誤來源.

解譯 SVG 或 HTML 文件
----------------

`DOMParser` 也可以用來解譯 SVG 文件或是 HTML 文件。可以依 MIME 格式，輸出三種不同格式. 如果 MIME 格式是 `text/xml`,輸出的格式為 `XMLDocument`, 如果 MIME 格式是 `image/svg+xml`, 輸出格式為 `SVGDocument,` 如果 MIME 格式是 `text/html`, 輸出格式則為 `HTMLDocument`.

```js
var parser = new DOMParser();
var doc = parser.parseFromString(stringContainingXMLSource, "application/xml");
// returns a Document, but not a SVGDocument nor a HTMLDocument

parser = new DOMParser();
doc = parser.parseFromString(stringContainingXMLSource, "image/svg+xml");
// returns a SVGDocument, which also is a Document.

parser = new DOMParser();
doc = parser.parseFromString(stringContainingHTMLSource, "text/html");
// returns a HTMLDocument, which also is a Document.
```

### 其他瀏覽器可用的 DOMParser HTML 外掛程式

```js
/\*
 \* DOMParser HTML extension
 \* 2012-09-04
 \*
 \* By Eli Grey, http://eligrey.com
 \* Public domain.
 \* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
 \*/

/\*! @source https://gist.github.com/1129031 \*/
/\*global document, DOMParser\*/

(function (DOMParser) {
  "use strict";

  var proto = DOMParser.prototype,
    nativeParse = proto.parseFromString;
  // Firefox/Opera/IE throw errors on unsupported types
  try {
    // WebKit returns null on unsupported types
    if (new DOMParser().parseFromString("", "text/html")) {
      // text/html parsing is natively supported
      return;
    }
  } catch (ex) {}

  proto.parseFromString = function (markup, type) {
    if (/^\s\*text\/html\s\*(?:;|$)/i.test(type)) {
      var doc = document.implementation.createHTMLDocument("");
      if (markup.toLowerCase().indexOf("<!doctype") > -1) {
        doc.documentElement.innerHTML = markup;
      } else {
        doc.body.innerHTML = markup;
      }
      return doc;
    } else {
      return nativeParse.apply(this, arguments);
    }
  };
})(DOMParser);
```

### DOMParser from Chrome/JSM/XPCOM/Privileged Scope

See article here: nsIDOMParser

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參考資料
----

* Parsing and serializing XML (en-US)
* XMLHttpRequest
* XMLSerializer (en-US)
* Parsing HTML to DOM


觸控事件 - Web APIs

觸控事件
====

為了支援基於觸碰的使用者介面，觸控事件提供了解釋手指或觸控筆於觸控螢幕或觸控板上活動的資訊。

觸控事件介面為相對低階的 API，可用來支援應用程式特定的多點觸控互動，例如兩指手勢。多點觸控互動起始於手指或觸控筆於平面的第一個觸碰，其它的手指可能於其後伴隨著移動才觸碰到平面。而互動則結束於手指自觸控平面離開。在此互動期間，應用程式會於開始、移動以及結束的階段接收到觸控事件。

觸控事件類似於滑鼠事件，但觸控事件支援同時間多個觸碰及其於觸控平面的每個不同點位置。`TouchEvent` (en-US) 介面封裝了所有當前作用中的觸碰點。`Touch` (en-US) 介面則表示個別的觸碰點，包括了如觸碰點於瀏覽器 viewport 中的相對位置資訊。

定義
--

平面（Surface）

The touch-sensitive surface. This may be a screen or trackpad.

觸碰點（Touch point）

A point of contact with the surface. This may be a finger (or elbow, ear, nose, whatever, but typically a finger) or stylus.

介面
--

`TouchEvent` (en-US)

Represents an event that occurs when the state of touches on the surface changes.

`Touch` (en-US)

Represents a single point of contact between the user and the touch surface.

`TouchList`

Represents a group of touches; this is used when the user has, for example, multiple fingers on the surface at the same time.

範例
--

This example tracks multiple touch points at a time, allowing the user to draw in a `<canvas>` with more than one finger at a time. It will only work on a browser that supports touch events.

**備註：** The text below uses the term "finger" when describing the contact with the surface, but it could, of course, also be a stylus or other contact method.

### Create a canvas

```html
<canvas id="canvas" width="600" height="600" style="border:solid black 1px;">
  Your browser does not support canvas element.
</canvas>
<br />
<button onclick="startup()">Initialize</button>
<br />
Log:
<pre id="log" style="border: 1px solid #ccc;"></pre>
```

### Setting up the event handlers

When the page loads, the `startup()` function shown below should be called by our `<body>` (en-US) element's `onload` attribute (but in the example we use a button to trigger it, due to limitations of the MDN live example system).

```js
function startup() {
  var el = document.getElementsByTagName("canvas")[0];
  el.addEventListener("touchstart", handleStart, false);
  el.addEventListener("touchend", handleEnd, false);
  el.addEventListener("touchcancel", handleCancel, false);
  el.addEventListener("touchmove", handleMove, false);
  log("initialized.");
}
```

This simply sets up all the event listeners for our `<canvas>` element so we can handle the touch events as they occur.

#### Tracking new touches

We'll keep track of the touches in-progress.

```js
var ongoingTouches = [];
```

When a `touchstart` (en-US) event occurs, indicating that a new touch on the surface has occurred, the `handleStart()` function below is called.

```js
function handleStart(evt) {
  evt.preventDefault();
  log("touchstart.");
  var el = document.getElementsByTagName("canvas")[0];
  var ctx = el.getContext("2d");
  var touches = evt.changedTouches;

  for (var i = 0; i < touches.length; i++) {
    log("touchstart:" + i + "...");
    ongoingTouches.push(copyTouch(touches[i]));
    var color = colorForTouch(touches[i]);
    ctx.beginPath();
    ctx.arc(touches[i].pageX, touches[i].pageY, 4, 0, 2 \* Math.PI, false); // a circle at the start
    ctx.fillStyle = color;
    ctx.fill();
    log("touchstart:" + i + ".");
  }
}
```

This calls `event.preventDefault()` to keep the browser from continuing to process the touch event (this also prevents a mouse event from also being delivered). Then we get the context and pull the list of changed touch points out of the event's `TouchEvent.changedTouches` (en-US) property.

After that, we iterate over all the `Touch` (en-US) objects in the list, pushing them onto an array of active touch points and drawing the start point for the draw as a small circle; we're using a 4-pixel wide line, so a 4 pixel radius circle will show up neatly.

#### Drawing as the touches move

Each time one or more fingers moves, a `touchmove` (en-US) event is delivered, resulting in our `handleMove()` function being called. Its responsibility in this example is to update the cached touch information and to draw a line from the previous position to the current position of each touch.

```js
function handleMove(evt) {
  evt.preventDefault();
  var el = document.getElementsByTagName("canvas")[0];
  var ctx = el.getContext("2d");
  var touches = evt.changedTouches;

  for (var i = 0; i < touches.length; i++) {
    var color = colorForTouch(touches[i]);
    var idx = ongoingTouchIndexById(touches[i].identifier);

    if (idx >= 0) {
      log("continuing touch " + idx);
      ctx.beginPath();
      log(
        "ctx.moveTo(" +
          ongoingTouches[idx].pageX +
          ", " +
          ongoingTouches[idx].pageY +
          ");",
      );
      ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
      log("ctx.lineTo(" + touches[i].pageX + ", " + touches[i].pageY + ");");
      ctx.lineTo(touches[i].pageX, touches[i].pageY);
      ctx.lineWidth = 4;
      ctx.strokeStyle = color;
      ctx.stroke();

      ongoingTouches.splice(idx, 1, copyTouch(touches[i])); // swap in the new touch record
      log(".");
    } else {
      log("can't figure out which touch to continue");
    }
  }
}
```

This iterates over the changed touches as well, but it looks in our cached touch information array for the previous information about each touch in order to determine the starting point for each touch's new line segment to be drawn. This is done by looking at each touch's `Touch.identifier` (en-US) property. This property is a unique integer for each touch, and remains consistent for each event during the duration of each finger's contact with the surface.

This lets us get the coordinates of the previous position of each touch and use the appropriate context methods to draw a line segment joining the two positions together.

After drawing the line, we call `Array.splice()` to replace the previous information about the touch point with the current information in the `ongoingTouches` array.

#### Handling the end of a touch

When the user lifts a finger off the surface, a `touchend` (en-US) event is sent. We handle both of these the same way: by calling the `handleEnd()` function below. Its job is to draw the last line segment for each touch that ended and remove the touch point from the ongoing touch list.

```js
function handleEnd(evt) {
  evt.preventDefault();
  log("touchend");
  var el = document.getElementsByTagName("canvas")[0];
  var ctx = el.getContext("2d");
  var touches = evt.changedTouches;

  for (var i = 0; i < touches.length; i++) {
    var color = colorForTouch(touches[i]);
    var idx = ongoingTouchIndexById(touches[i].identifier);

    if (idx >= 0) {
      ctx.lineWidth = 4;
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
      ctx.lineTo(touches[i].pageX, touches[i].pageY);
      ctx.fillRect(touches[i].pageX - 4, touches[i].pageY - 4, 8, 8); // and a square at the end
      ongoingTouches.splice(idx, 1); // remove it; we're done
    } else {
      log("can't figure out which touch to end");
    }
  }
}
```

This is very similar to the previous function; the only real differences are that we draw a small square to mark the end and that when we call `Array.splice()`, we simply remove the old entry from the ongoing touch list, without adding in the updated information. The result is that we stop tracking that touch point.

#### Handling canceled touches

If the user's finger wanders into browser UI, or the touch otherwise needs to be canceled, the `touchcancel` (en-US) event is sent, and we call the `handleCancel()` function below.

```js
function handleCancel(evt) {
  evt.preventDefault();
  log("touchcancel.");
  var touches = evt.changedTouches;

  for (var i = 0; i < touches.length; i++) {
    var idx = ongoingTouchIndexById(touches[i].identifier);
    ongoingTouches.splice(idx, 1); // remove it; we're done
  }
}
```

Since the idea is to immediately abort the touch, we simply remove it from the ongoing touch list without drawing a final line segment.

### Convenience functions

This example uses two convenience functions that should be looked at briefly to help make the rest of the code more clear.

#### Selecting a color for each touch

In order to make each touch's drawing look different, the `colorForTouch()` function is used to pick a color based on the touch's unique identifier. This identifier is an opaque number, but we can at least rely on it differing between the currently-active touches.

```js
function colorForTouch(touch) {
  var r = touch.identifier % 16;
  var g = Math.floor(touch.identifier / 3) % 16;
  var b = Math.floor(touch.identifier / 7) % 16;
  r = r.toString(16); // make it a hex digit
  g = g.toString(16); // make it a hex digit
  b = b.toString(16); // make it a hex digit
  var color = "#" + r + g + b;
  log("color for touch with identifier " + touch.identifier + " = " + color);
  return color;
}
```

The result from this function is a string that can be used when calling `<canvas>` functions to set drawing colors. For example, for a `Touch.identifier` (en-US) value of 10, the resulting string is "#aaa".

#### Copying a touch object

Some browsers (mobile Safari, for one) re-use touch objects between events, so it's best to copy the bits you care about, rather than referencing the entire object.

```js
function copyTouch(touch) {
  return {
    identifier: touch.identifier,
    pageX: touch.pageX,
    pageY: touch.pageY,
  };
}
```

#### Finding an ongoing touch

The `ongoingTouchIndexById()` function below scans through the `ongoingTouches` array to find the touch matching the given identifier, then returns that touch's index into the array.

```js
function ongoingTouchIndexById(idToFind) {
  for (var i = 0; i < ongoingTouches.length; i++) {
    var id = ongoingTouches[i].identifier;

    if (id == idToFind) {
      return i;
    }
  }
  return -1; // not found
}
```

#### Showing what's going on

```js
function log(msg) {
  var p = document.getElementById("log");
  p.innerHTML = msg + "\n" + p.innerHTML;
}
```

If your browser supports it, you can see it live.

jsFiddle example

Additional tips
---------------

This section provides additional tips on how to handle touch events in your web application.

### Handling clicks

Since calling `preventDefault()` on a `touchstart` (en-US) or the first `touchmove` (en-US) event of a series prevents the corresponding mouse events from firing, it's common to call `preventDefault()` on `touchmove` (en-US) rather than `touchstart` (en-US). That way, mouse events can still fire and things like links will continue to work. Alternatively, some frameworks have taken to refiring touch events as mouse events for this same purpose. (This example is oversimplified and may result in strange behavior. It is only intended as a guide.)

```js
function onTouch(evt) {
  evt.preventDefault();
  if (
    evt.touches.length > 1 ||
    (evt.type == "touchend" && evt.touches.length > 0)
  )
    return;

  var newEvt = document.createEvent("MouseEvents");
  var type = null;
  var touch = null;

  switch (evt.type) {
    case "touchstart":
      type = "mousedown";
      touch = evt.changedTouches[0];
      break;
    case "touchmove":
      type = "mousemove";
      touch = evt.changedTouches[0];
      break;
    case "touchend":
      type = "mouseup";
      touch = evt.changedTouches[0];
      break;
  }

  newEvt.initMouseEvent(
    type,
    true,
    true,
    evt.originalTarget.ownerDocument.defaultView,
    0,
    touch.screenX,
    touch.screenY,
    touch.clientX,
    touch.clientY,
    evt.ctrlKey,
    evt.altKey,
    evt.shiftKey,
    evt.metaKey,
    0,
    null,
  );
  evt.originalTarget.dispatchEvent(newEvt);
}
```

### Calling preventDefault() only on a second touch

One technique for preventing things like `pinchZoom` on a page is to call `preventDefault()` on the second touch in a series. This behavior is not well defined in the touch events spec, and results in different behavior for different browsers (i.e., iOS will prevent zooming but still allow panning with both fingers; Android will allow zooming but not panning; Opera and Firefox currently prevent all panning and zooming.) Currently, it's not recommended to depend on any particular behavior in this case, but rather to depend on meta viewport to prevent zooming.

規範
--

| Specification |
| --- |
| Touch Events  |

瀏覽器相容性
------

### api.Touch

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.TouchEvent

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.TouchList

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.