使用 XMLHttpRequest - Web APIs

使用 XMLHttpRequest
=================

要送出一個 HTTP 請求，需要建立一個 `XMLHttpRequest` 物件、開啟一個 URL，並發起一個請求。在交易（transaction）完成後，`XMLHttpRequest` 物件將會包含如回應內容（response body）及 HTTP 狀態等等請求結果中的有用資訊。本頁概述了一些常見的、甚至略為難理解的 `XMLHttpRequest` 物件使用案例。

```js
function reqListener() {
  console.log(this.responseText);
}

var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send();
```

請求類型
----

透過 `XMLHttpRequest` 建立的請求，其取得資料的方式可以為非同步（asynchronously）或同步（synchronously）兩種之一。請求的種類是由 `XMLHttpRequest.open()` (en-US) 方法的選擇性參數 `async`（第三個參數）決定。若 `async` 參數為 `true` 或是未指定，`XMLHttpRequest` 會被設定為非同步，相反的若為 `false` 則會被設定為同步。這兩種請求類型的細節討論與示範可以在同步與非同步請求頁面中找到。一般來說，很少會使用到同步請求。

**備註：** 自 Gecko 30.0 開始，在主執行緒上的同步請求因其差勁的使用者體驗已被棄用。

處理回應
----

`XMLHttpRequest` 的活動標準規範（living standard specification）定義了數個 `XMLHttpRequest` 建構出之物件的回應屬性。這些回應屬性告訴客戶端關於 `XMLHttpRequest` 回應狀態的重要資訊。一些處理非文字類型回應的案例可能會需要一些在下面小節所說明的分析和操作。

### 分析及操作 `responseXML` 屬性

透過 `XMLHttpRequest` 取得一個遠端的 XML 文件內容時，`responseXML` 屬性（property）將會是一個由 XML 文件解析而來的 DOM 物件。這可能會造成分析和操作上的一些困難，以下有四種主要的 XML 文件分析方式：

1. 利用 XPath 指向需要部份。
2. 手動的解析與序列化 XML 成字串或物件。
3. 利用 `XMLSerializer` (en-US) 來序列化 **DOM 樹成字串或檔案**。
4. 如果事先知道 XML 文件內容，可利用 `RegExp` (en-US)。如果換行符號會影響 `RegExp` 掃描結果，則需要移除換行符號。然而，這項方式應該是「最後不得已的手段（last resort）」，因為一旦 XML 文件內容稍有變動，此方式就可能會失敗。
### 分析及操作含有 HTML 文件的 `responseText` 屬性

**備註：** W3C 的XMLHttpRequest 規範允許透過 `XMLHttpRequest.responseXML` 屬性（property）來解析 HTML。相關細節請參考 HTML in XMLHttpRequest 一文。

若透過 `XMLHttpRequest` 來取得一個遠端的 HTML 網頁內容，則 `responseText` 屬性（property）會是「一串（soup）」包含所有 HTML 標籤的字串。這可能使得在分析和操作上造成困難，以下有三種主要分析此一大串 HTML 字串的方式：

1. 利用 `XMLHttpRequest.responseXML` 屬性。
2. 將內容透過 `fragment.body.innerHTML` 注入文件片段（document fragment）之 `body` 中，並遍歷（traverse）文件片段的 DOM。
3. 如果事先知道 HTML 之 `responseText` 內容，可利用 `RegExp` (en-US)。如果換行符號會影響 `RegExp` 掃描結果，則需要移除換行符號。然而，這項方式應該是「最後不得已的手段（last resort）」，因為一旦 HTML 程式碼稍有變動，此方式就可能會失敗。
處理二進位資料
-------

僅管 `XMLHttpRequest` 最常被用在傳送及接收文字資料，但它其實也可以傳送及接收二進位內容。有幾種經過良好測試的方法可以用來強制使用 `XMLHttpRequest` 發送二進位資料。透過使用 `XMLHttpRequest` 物件的 `.overrideMimeType()` 方法是一個可行的解決方案。

```js
var oReq = new XMLHttpRequest();
oReq.open("GET", url);
// retrieve data unprocessed as a binary string
oReq.overrideMimeType("text/plain; charset=x-user-defined");
/\* ... \*/
```

XMLHttpRequest Level 2 規範加入了新的 `responseType` 屬性，讓收發二進位資料變得容易許多。

```js
var oReq = new XMLHttpRequest();

oReq.onload = function (e) {
  var arraybuffer = oReq.response; // not responseText
  /\* ... \*/
};
oReq.open("GET", url);
oReq.responseType = "arraybuffer";
oReq.send();
```

更多的範例可參考傳送及接收二進位資料頁面。

監視進度
----

`XMLHttpRequest` 提供了監聽請求於處理過程中所發生的各項事件之能力。包括了定期進度通知、錯誤通知等等。

`XMLHttpRequest` 支援可監視其傳輸進度的 DOM 進度事件，此事件遵循進度事件規範：這些事件實作了 `ProgressEvent` (en-US) 介面。

```js
var oReq = new XMLHttpRequest();

oReq.addEventListener("progress", updateProgress);
oReq.addEventListener("load", transferComplete);
oReq.addEventListener("error", transferFailed);
oReq.addEventListener("abort", transferCanceled);

oReq.open();

// ...

// progress on transfers from the server to the client (downloads)
function updateProgress(oEvent) {
  if (oEvent.lengthComputable) {
    var percentComplete = oEvent.loaded / oEvent.total;
    // ...
  } else {
    // Unable to compute progress information since the total size is unknown
  }
}

function transferComplete(evt) {
  console.log("The transfer is complete.");
}

function transferFailed(evt) {
  console.log("An error occurred while transferring the file.");
}

function transferCanceled(evt) {
  console.log("The transfer has been canceled by the user.");
}
```

第 3-6 行加入了事件監聽器來處理使用 `XMLHttpRequest` 執行資料收發過程中的各類事件。

**備註：** 必須在呼叫 `open()` 方法開啟請求連線之前就註冊好事件監聽器，否則 `progress` 事件將不會被觸發。

在這個例子中，指定了 `updateProgress()` 函式作為 `progress` 事件處理器，`progress` 事件處理器會於 `progress` 事件物件的 `total` 及 `loaded` 屬性分別接收到要傳輸的總位元數及已送出的位元數。然而，假如 `lengthComputable` 屬性值為假，則代表要傳輸的總位元數是未知且 `total` 屬性值將會為零。

`progress` 事件同時存在於上傳及下載傳輸中。下載的相關事件會於 `XMLHttpRequest` 物件自己身上被觸發，如上面的範例。而上傳相關事件則在 `XMLHttpRequest.upload` 物件上被觸發，如以下範例：

```js
var oReq = new XMLHttpRequest();

oReq.upload.addEventListener("progress", updateProgress);
oReq.upload.addEventListener("load", transferComplete);
oReq.upload.addEventListener("error", transferFailed);
oReq.upload.addEventListener("abort", transferCanceled);

oReq.open();
```

**備註：** `progress` 事件無法用於 `file:` 通訊協定。

**備註：** 自 Gecko 9.0 開始，接收到每一個資料的區塊（chunk）時，`progress` 事件都會被觸發。包括在 `progress` 事件被觸發前，就已經接收到含有最後一個資料區塊的最後一個封包並且關閉連線的狀況下，在載入此封包時仍會自動觸發 `progress` 事件。這代表我們可以僅關注 `progress` 事件即能夠可靠的監視進度。

**備註：** 在 Gecko 12.0 中，如果 `XMLHttpRequest` 的 `responseType` 屬性為「moz-blob」，那麼 `progress` 事件觸發時的 `XMLHttpRequest.response` 值會是一個目前包含了所接收資料的 `Blob`。

我們也可以透過 `loadend` 事件來偵測到所有之三種下載結束狀況（`abort`、`load` 或 `error`）：

```js
req.addEventListener("loadend", loadEnd);

function loadEnd(e) {
  console.log(
    "The transfer finished (although we don't know if it succeeded or not).",
  );
}
```

請注意由 `loadend` 事件中接收到的資訊並無法確定是由何種結束狀況所觸發。不過還是可以用 `loadend` 事件來處理所有傳輸結束情況下需要執行的任務。

提交表單與上傳檔案
---------

`XMLHttpRequest` 物件實體有兩種方式來提交表單：

* 僅使用 AJAX
* 使用 `FormData` API

 使用 `FormData` API 是最簡單、快速的方式，但不利於將資料集合進行字串化。
 只使用 AJAX 的方式較為複雜，但也更加靈活、強大。

### 僅使用 `XMLHttpRequest`

以不透過 `FormData` API 提交表單的方式在大多數的情況下都不需要使用其他額外的 API。唯一的例外是**要上傳一或多個檔案**時，會需要用到 `FileReader` API。

#### 提交方法簡介

一個 HTML 表單（form） (en-US)有以下四種提交方式：

* 使用 `POST` 方法，並且設定 `enctype` 屬性（attribute）為 `application/x-www-form-urlencoded`（預設值）。
* 使用 `POST` 方法，並且設定 `enctype` 屬性為 `text/plain`。
* 使用 `POST` 方法，並且設定 `enctype` 屬性為 `multipart/form-data`。
* 使用 `GET` 方法（在此情況下，`enctype` 屬性將會被忽略）。

現在，假設要提交一個只包含兩個欄位的表單，欄位名稱為 `foo` 及 `baz`。若是使用 `POST` 方法，伺服器將會收到一個如以下三個例子之一的字串，這取決於所使用的編碼類型（encoding type）：

* 方法：`POST`；編碼類型：`application/x-www-form-urlencoded`（預設值）：
```

Content-Type: application/x-www-form-urlencoded

foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
```

* 方法：`POST`；編碼類型：`text/plain`：
```

Content-Type: text/plain

foo=bar
baz=The first line.
The second line.
```

* 方法：`POST`；編碼類型：`multipart/form-data`：
```

Content-Type: multipart/form-data; boundary=---------------------------314911788813839

-----------------------------314911788813839
Content-Disposition: form-data; name="foo"

bar
-----------------------------314911788813839
Content-Disposition: form-data; name="baz"

The first line.
The second line.

-----------------------------314911788813839--
```

如果是使用 `GET` 方法，一個如下方的字串會被直接附加入到 URL 上：
```

?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
```

#### 小型原生框架

在我們提交 `<form>` (en-US) 時，瀏覽器自動幫我們做了上面這些工作。假如要使用 JavaScript 達到同樣的效果就必須告訴直譯器（interpreter）要處理的*所有事*。然而，如何透過*純粹的* AJAX 來傳送表單複雜到難以在本頁解釋所有細節。基於這個理由，我們改為在這此提供**一組完整（教學用）的框架**，可用於上述四種的每一種*提交*（submit），並包括**上傳檔案**：
```

<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Sending forms with pure AJAX – MDN</title>
    <script type="text/javascript">
 "use strict";

 /\*\
|\*|
|\*| :: XMLHttpRequest.prototype.sendAsBinary() Polyfill ::
|\*|
|\*| https://developer.mozilla.org/zh-TW/docs/DOM/XMLHttpRequest#sendAsBinary()
\\*/

 if (!XMLHttpRequest.prototype.sendAsBinary) {
 XMLHttpRequest.prototype.sendAsBinary = function (sData) {
 var nBytes = sData.length,
 ui8Data = new Uint8Array(nBytes);
 for (var nIdx = 0; nIdx < nBytes; nIdx++) {
 ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
 }
 /\* send as ArrayBufferView...: \*/
 this.send(ui8Data);
 /\* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); \*/
 };
 }

 /\*\
|\*|
|\*| :: AJAX Form Submit Framework ::
|\*|
|\*| https://developer.mozilla.org/zh-TW/docs/DOM/XMLHttpRequest\_API/Using\_XMLHttpRequest
|\*|
|\*| This framework is released under the GNU Public License, version 3 or later.
|\*| https://www.gnu.org/licenses/gpl-3.0-standalone.html
|\*|
|\*| Syntax:
|\*|
|\*| AJAXSubmit(HTMLFormElement);
\\*/

 var AJAXSubmit = (function () {
 function ajaxSuccess() {
 /\* console.log("AJAXSubmit - Success!"); \*/
 console.log(this.responseText);
 /\* you can get the serialized data through the "submittedData" custom property: \*/
 /\* console.log(JSON.stringify(this.submittedData)); \*/
 }

 function submitData(oData) {
 /\* the AJAX request... \*/
 var oAjaxReq = new XMLHttpRequest();
 oAjaxReq.submittedData = oData;
 oAjaxReq.onload = ajaxSuccess;
 if (oData.technique === 0) {
 /\* method is GET \*/
 oAjaxReq.open(
 "get",
 oData.receiver.replace(
 /(?:\?.\*)?$/,
 oData.segments.length > 0 ? "?" + oData.segments.join("&") : "",
 ),
 true,
 );
 oAjaxReq.send(null);
 } else {
 /\* method is POST \*/
 oAjaxReq.open("post", oData.receiver, true);
 if (oData.technique === 3) {
 /\* enctype is multipart/form-data \*/
 var sBoundary =
 "---------------------------" + Date.now().toString(16);
 oAjaxReq.setRequestHeader(
 "Content-Type",
 "multipart\/form-data; boundary=" + sBoundary,
 );
 oAjaxReq.sendAsBinary(
 "--" +
 sBoundary +
 "\r\n" +
 oData.segments.join("--" + sBoundary + "\r\n") +
 "--" +
 sBoundary +
 "--\r\n",
 );
 } else {
 /\* enctype is application/x-www-form-urlencoded or text/plain \*/
 oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
 oAjaxReq.send(
 oData.segments.join(oData.technique === 2 ? "\r\n" : "&"),
 );
 }
 }
 }

 function processStatus(oData) {
 if (oData.status > 0) {
 return;
 }
 /\* the form is now totally serialized! do something before sending it to the server... \*/
 /\* doSomething(oData); \*/
 /\* console.log("AJAXSubmit - The form is now serialized. Submitting..."); \*/
 submitData(oData);
 }

 function pushSegment(oFREvt) {
 this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
 this.owner.status--;
 processStatus(this.owner);
 }

 function plainEscape(sText) {
 /\* How should I treat a text/plain form encoding?
 What characters are not allowed? this is what I suppose...: \*/
 /\* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" \*/
 return sText.replace(/[\s\=\\]/g, "\\$&");
 }

 function SubmitRequest(oTarget) {
 var nFile,
 sFieldType,
 oField,
 oSegmReq,
 oFile,
 bIsPost = oTarget.method.toLowerCase() === "post";
 /\* console.log("AJAXSubmit - Serializing form..."); \*/
 this.contentType =
 bIsPost && oTarget.enctype
 ? oTarget.enctype
 : "application\/x-www-form-urlencoded";
 this.technique = bIsPost
 ? this.contentType === "multipart\/form-data"
 ? 3
 : this.contentType === "text\/plain"
 ? 2
 : 1
 : 0;
 this.receiver = oTarget.action;
 this.status = 0;
 this.segments = [];
 var fFilter = this.technique === 2 ? plainEscape : escape;
 for (var nItem = 0; nItem < oTarget.elements.length; nItem++) {
 oField = oTarget.elements[nItem];
 if (!oField.hasAttribute("name")) {
 continue;
 }
 sFieldType =
 oField.nodeName.toUpperCase() === "INPUT"
 ? oField.getAttribute("type").toUpperCase()
 : "TEXT";
 if (sFieldType === "FILE" && oField.files.length > 0) {
 if (this.technique === 3) {
 /\* enctype is multipart/form-data \*/
 for (nFile = 0; nFile < oField.files.length; nFile++) {
 oFile = oField.files[nFile];
 oSegmReq = new FileReader();
 /\* (custom properties:) \*/
 oSegmReq.segmentIdx = this.segments.length;
 oSegmReq.owner = this;
 /\* (end of custom properties) \*/
 oSegmReq.onload = pushSegment;
 this.segments.push(
 'Content-Disposition: form-data; name="' +
 oField.name +
 '"; filename="' +
 oFile.name +
 '"\r\nContent-Type: ' +
 oFile.type +
 "\r\n\r\n",
 );
 this.status++;
 oSegmReq.readAsBinaryString(oFile);
 }
 } else {
 /\* enctype is application/x-www-form-urlencoded or text/plain or
 method is GET: files will not be sent! \*/
 for (
 nFile = 0;
 nFile < oField.files.length;
 this.segments.push(
 fFilter(oField.name) +
 "=" +
 fFilter(oField.files[nFile++].name),
 )
 );
 }
 } else if (
 (sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") ||
 oField.checked
 ) {
 /\* NOTE: this will submit \_all\_ submit buttons. Detecting the correct one is non-trivial. \*/
 /\* field type is not FILE or is FILE but is empty \*/
 this.segments.push(
 this.technique === 3 /\* enctype is multipart/form-data \*/
 ? 'Content-Disposition: form-data; name="' +
 oField.name +
 '"\r\n\r\n' +
 oField.value +
 "\r\n"
 : /\* enctype is application/x-www-form-urlencoded or text/plain or method is GET \*/
 fFilter(oField.name) + "=" + fFilter(oField.value),
 );
 }
 }
 processStatus(this);
 }

 return function (oFormElement) {
 if (!oFormElement.action) {
 return;
 }
 new SubmitRequest(oFormElement);
 };
 })();
 </script>
  </head>
  <body>
    <h1>Sending forms with pure AJAX</h1>

    <h2>Using the GET method</h2>

    <form
 action="register.php"
 method="get"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h2>Using the POST method</h2>
    <h3>Enctype: application/x-www-form-urlencoded (default)</h3>

    <form
 action="register.php"
 method="post"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: text/plain</h3>

    <form
 action="register.php"
 method="post"
 enctype="text/plain"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>Your name: <input type="text" name="user" /></p>
        <p>
          Your message:<br />
          <textarea name="message" cols="40" rows="8"></textarea>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: multipart/form-data</h3>

    <form
 action="register.php"
 method="post"
 enctype="multipart/form-data"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Upload example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" /><br />
          Sex:
          <input id="sex\_male" type="radio" name="sex" value="male" />
          <label for="sex\_male">Male</label>
          <input id="sex\_female" type="radio" name="sex" value="female" />
          <label for="sex\_female">Female</label><br />
          Password: <input type="password" name="secret" /><br />
          What do you prefer:
          <select name="image\_type">
            <option>Books</option>
            <option>Cinema</option>
            <option>TV</option>
          </select>
        </p>
        <p>
          Post your photos:
          <input type="file" multiple name="photos[]" />
        </p>
        <p>
          <input
 id="vehicle\_bike"
 type="checkbox"
 name="vehicle[]"
 value="Bike" />
          <label for="vehicle\_bike">I have a bike</label><br />
          <input
 id="vehicle\_car"
 type="checkbox"
 name="vehicle[]"
 value="Car" />
          <label for="vehicle\_car">I have a car</label>
        </p>
        <p>
          Describe yourself:<br />
          <textarea name="description" cols="50" rows="8"></textarea>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>
  </body>
</html>
```

為了進行測試，建立一個名為 **register.php** 的 PHP 頁面（即為上面範例表單之 `action` 屬性（attribute）所指向的位置），並輸入以下*最簡化*的內容：

```php
<?php
/\* register.php \*/

header("Content-type: text/plain");

/\*
NOTE: You should never use `print\_r()` in production scripts, or
otherwise output client-submitted data without sanitizing it first.
Failing to sanitize can lead to cross-site scripting vulnerabilities.
\*/

echo ":: data received via GET ::\n\n";
print\_r($\_GET);

echo "\n\n:: Data received via POST ::\n\n";
print\_r($\_POST);

echo "\n\n:: Data received as \"raw\" (text/plain encoding) ::\n\n";
if (isset($HTTP\_RAW\_POST\_DATA)) { echo $HTTP\_RAW\_POST\_DATA; }

echo "\n\n:: Files received ::\n\n";
print\_r($\_FILES);
```

使用這個框架的語法簡單如下：
```

AJAXSubmit(myForm);
```

**備註：** 此框架使用了 `FileReader` API 來發送檔案上傳。這是個較新的 API，且 IE9 或其先前版本並未實作。因為這個理由，AJAX-only 上傳被認為是**一項實驗性技術**。若沒有需要上傳二進位檔案，此框架可於大部分瀏覽器中運作良好。

**備註：** 傳送二進位檔案的最佳方式是藉由 `ArrayBuffers` 或 `Blobs` 結合 `send()` (en-US) 方法來送出，如果可以也能搭配 `FileReader` API 的 `readAsArrayBuffer()` (en-US) 方法先進行讀取。但因為這段程式指令碼（script）的目的是要處理可字串化的 (en-US)原始資料，所以使用 `sendAsBinary()` 方法結合 `FileReader` API 的 `readAsBinaryString()` (en-US) 方法。就其本身來看，以上的指令碼只有在處理小型檔案時才有意義。假如不打算上傳二進位內容，請考慮使用 `FormData` API。

**備註：** 非標準的 `sendAsBinary` 方法在 Gecko 31 已被認為是棄用的（deprecated），並且即將被移除。而標準的 `send(Blob data)` 方法可以作為替代。

### 使用 FormData 物件

`FormData` 建構式可以讓我們收集一連串名／值對資料並透過 `XMLHttpRequest` 送出。其主要用於傳送表單資料，但也能夠單獨的由表單建立來傳輸使用者輸入的資料。若表單的編碼類型（encoding type）被設定為「multipart/form-data」，則由 `FormData` 所發送的資料格式和表單用來傳送資料的 `submit()` 方法相同。FormData 物件可以搭配 `XMLHttpRequest` 以多種方式使用。相關的範例，以及可以怎麼利用 FormData 配合 XMLHttpRequest 的說明，請參考使用 FormData 物件頁面。為了教學使用，下方為**一個利用 `FormData` API 來改寫先前範例的*翻譯*版本**。注意這段精簡後的程式碼：
```

<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" charset="UTF-8" />
    <title>Sending forms with FormData – MDN</title>
    <script>
 "use strict";

 function ajaxSuccess() {
 console.log(this.responseText);
 }

 function AJAXSubmit(oFormElement) {
 if (!oFormElement.action) {
 return;
 }
 var oReq = new XMLHttpRequest();
 oReq.onload = ajaxSuccess;
 if (oFormElement.method.toLowerCase() === "post") {
 oReq.open("post", oFormElement.action);
 oReq.send(new FormData(oFormElement));
 } else {
 var oField,
 sFieldType,
 nFile,
 sSearch = "";
 for (var nItem = 0; nItem < oFormElement.elements.length; nItem++) {
 oField = oFormElement.elements[nItem];
 if (!oField.hasAttribute("name")) {
 continue;
 }
 sFieldType =
 oField.nodeName.toUpperCase() === "INPUT"
 ? oField.getAttribute("type").toUpperCase()
 : "TEXT";
 if (sFieldType === "FILE") {
 for (
 nFile = 0;
 nFile < oField.files.length;
 sSearch +=
 "&" +
 escape(oField.name) +
 "=" +
 escape(oField.files[nFile++].name)
 );
 } else if (
 (sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") ||
 oField.checked
 ) {
 sSearch += "&" + escape(oField.name) + "=" + escape(oField.value);
 }
 }
 oReq.open(
 "get",
 oFormElement.action.replace(
 /(?:\?.\*)?$/,
 sSearch.replace(/^&/, "?"),
 ),
 true,
 );
 oReq.send(null);
 }
 }
 </script>
  </head>
  <body>
    <h1>Sending forms with FormData</h1>

    <h2>Using the GET method</h2>

    <form
 action="register.php"
 method="get"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h2>Using the POST method</h2>
    <h3>Enctype: application/x-www-form-urlencoded (default)</h3>

    <form
 action="register.php"
 method="post"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Registration example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: text/plain</h3>

    <p>The text/plain encoding is not supported by the FormData API.</p>

    <h3>Enctype: multipart/form-data</h3>

    <form
 action="register.php"
 method="post"
 enctype="multipart/form-data"
 onsubmit="AJAXSubmit(this); return false;">
      <fieldset>
        <legend>Upload example</legend>
        <p>
          First name: <input type="text" name="firstname" /><br />
          Last name: <input type="text" name="lastname" /><br />
          Sex:
          <input id="sex\_male" type="radio" name="sex" value="male" />
          <label for="sex\_male">Male</label>
          <input id="sex\_female" type="radio" name="sex" value="female" />
          <label for="sex\_female">Female</label><br />
          Password: <input type="password" name="secret" /><br />
          What do you prefer:
          <select name="image\_type">
            <option>Books</option>
            <option>Cinema</option>
            <option>TV</option>
          </select>
        </p>
        <p>
          Post your photos:
          <input type="file" multiple name="photos[]" />
        </p>
        <p>
          <input
 id="vehicle\_bike"
 type="checkbox"
 name="vehicle[]"
 value="Bike" />
          <label for="vehicle\_bike">I have a bike</label><br />
          <input
 id="vehicle\_car"
 type="checkbox"
 name="vehicle[]"
 value="Car" />
          <label for="vehicle\_car">I have a car</label>
        </p>
        <p>
          Describe yourself:<br />
          <textarea name="description" cols="50" rows="8"></textarea>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>
  </body>
</html>
```

**備註：** 如同之前所說，**`FormData` 物件是不能被字串化的物件**。若想要字串化一個被提交的資料，請使用先前的*純* AJAX 範例。還要注意的是，雖然在這個例子中有一些 `file` `<input>` (en-US) 欄位，**當你透過 `FormData` API 來提交表單便也不需要使用 `FileReader` API**：檔案會自動地載入並上傳。

取得最後修改日期
--------

```js
function getHeaderTime() {
  console.log(
    this.getResponseHeader("Last-Modified"),
  ); /\* A valid GMTString date or null \*/
}

var oReq = new XMLHttpRequest();
oReq.open("HEAD" /\* use HEAD if you only need the headers! \*/, "yourpage.html");
oReq.onload = getHeaderTime;
oReq.send();
```

### 當最後修改日期改變時做一些事

先建立兩個函式：

```js
function getHeaderTime() {
  var nLastVisit = parseFloat(
    window.localStorage.getItem("lm\_" + this.filepath),
  );
  var nLastModif = Date.parse(this.getResponseHeader("Last-Modified"));

  if (isNaN(nLastVisit) || nLastModif > nLastVisit) {
    window.localStorage.setItem("lm\_" + this.filepath, Date.now());
    isFinite(nLastVisit) && this.callback(nLastModif, nLastVisit);
  }
}

function ifHasChanged(sURL, fCallback) {
  var oReq = new XMLHttpRequest();
  oReq.open("HEAD" /\* use HEAD - we only need the headers! \*/, sURL);
  oReq.callback = fCallback;
  oReq.filepath = sURL;
  oReq.onload = getHeaderTime;
  oReq.send();
}
```

並進行測試：

```js
/\* Let's test the file "yourpage.html"... \*/

ifHasChanged("yourpage.html", function (nModif, nVisit) {
  console.log(
    "The page '" +
      this.filepath +
      "' has been changed on " +
      new Date(nModif).toLocaleString() +
      "!",
  );
});
```

如果想要知道**目前頁面是否已變更**，請參考 `document.lastModified` (en-US) 一文。

跨網域 XMLHttpRequest
------------------

現代瀏覽器支援跨網域（cross-site）請求並實作了網路應用程式工作小組（Web Applications (WebApps) Working Group）提出的跨網域請求存取控制標準。只要伺服器被設定為允許來自你的網路應用程式來源（origin）網域之請求，`XMLHttpRequest` 便能正常運作。否則，將會拋出一個 `INVALID_ACCESS_ERR` 例外。

避開快取
----

有一個跨瀏覽器相容的避開快取方法，便是將時間戳記（timestamp）附加於 URL 後方，請確保加上了適當的「?」或「&」。例如：
```

http://foo.com/bar.html -> http://foo.com/bar.html?12345
http://foo.com/bar.html?foobar=baz -> http://foo.com/bar.html?foobar=baz&12345
```

由於本地快取的索引是基於 URL，加入時間戳記會導致每一個請求都會是唯一的，藉此避開快取。

可以使用以下的程式碼來自動的調整 URL：

```js
var oReq = new XMLHttpRequest();

oReq.open("GET", url + (/\?/.test(url) ? "&" : "?") + new Date().getTime());
oReq.send(null);
```

安全性
---

開啟跨網域指令碼（script）的建議方式是於 XMLHttpRequest 的回應中使用 `Access-Control-Allow-Origin` HTTP 標頭。

### 被中止的 XMLHttpRequest

如果你發現 `XMLHttpRequest` 的 `status=0` 且 `statusText=null`，這代表請求並不被允許執行，其狀態為 `UNSENT（未送出）`。被中止的原因可能是因為 `XMLHttpRequest` 物件所關聯的 origin（來源網域）值（於 `XMLHttpRequest` 物件建立時自 `window.origin` 取得）在呼叫 `open()` 方法之前就已經被改變。這是可能發生的，例如在 `window` 的 `onunload` 事件觸發時送出 `XMLHttpRequest` 請求，預期的情況為：`XMLHttpRequest` 物件剛被建立，而目前的視窗尚未關閉，而最後發送請求（即呼叫了 `open()` 方法）的時間點是在此視窗失去了焦點並且另外的視窗取得焦點之間。要避開這個問題的最有效方法是在要被終止的（terminated）`window` 觸發 `unload` 事件時，於新的 `window` 的上註冊一個新的 `activate` 事件監聽器來發送請求。

使用 JavaScript 模組／XPCOM 元件中的 XMLHttpRequest
------------------------------------------

自 JavaScript 模組 或 XPCOM 元件實體化一個 `XMLHttpRequest` 物件在做法上會有些許不同；我們無法用 `XMLHttpRequest()` 建構式，因為此建構式並未在元件中定義，並會導致程式產生錯誤。較佳的方式是使用 XPCOM 元件的建構式。

```js
const XMLHttpRequest = Components.Constructor(
  "@mozilla.org/xmlextras/xmlhttprequest;1",
  "nsIXMLHttpRequest",
);
```

在 Gecko 16 之前，存在著一個透過這種方式發送的請求會被無條件取消的臭蟲。若程式需要在 Gecko 15 或更早的版本上運作，可以從隱藏的 DOM window 中取得 `XMLHttpRequest()` 建構式。

```js
const { XMLHttpRequest } = Components.classes[
  "@mozilla.org/appshell/appShellService;1"
].getService(Components.interfaces.nsIAppShellService).hiddenDOMWindow;
var oReq = new XMLHttpRequest();
```

參見
--

* XMLHttpRequest 中的 HTML (en-US)
* HTTP 存取控制
* XMLHttpRequest - REST and the Rich User Experience
* "Using the XMLHttpRequest Object" (jibbering.com)
* The `XMLHttpRequest` object: WHATWG specification


Window.print() - Web APIs

Window.print()
==============

摘要
--

打開列印視窗來列印當前的文件。

語法
--
```

window.print()
```

注釋
--

Starting with Chrome V46.0 this method is blocked inside an `<iframe>` (en-US) unless its sandbox attribute has the value `allow-modals`.

規範
--

| Specification |
| --- |
| HTML Standard # printing |

參見
--

* Printing
* `window.onbeforeprint` (en-US)
* `window.onafterprint` (en-US)


Window.localStorage - Web APIs

Window.localStorage
===================

**`localStorage`** 為一唯讀屬性, 此屬性允許你存取目前文件(`Document` (en-US))隸屬網域來源的 `Storage` 物件; 與 sessionStorage 不同的是其儲存資料的可存取範圍為跨瀏覽頁狀態(Browser Sessions). `localStorage` 的應用與 `sessionStorage` 相似, 除了 `localStorage` 的儲存資料並無到期的限制, 而 `sessionStorage` 的儲存資料於目前瀏覽頁狀態結束的同時將一併被清除 — 也就是目前瀏覽器頁面被關閉的同時.

值得注意的是不論 `localStorage` 或者 `sessionStorage` **皆為專屬於目前瀏覽器頁面的通訊協定(Protocol)**.

鍵值名稱和值皆為**字串型式**(請留意, 當其為物件, 整數等將自動轉換為字串型式).

Syntax
------
```

myStorage = window.localStorage;
```

### Value

`Storage` 物件 which can be used to access the current origin's local storage space.

### Exceptions

`SecurityError`

The request violates a policy decision, or the origin is not a valid scheme/host/port tuple (this can happen if the origin uses the `file:` or `data:` scheme, for example). 舉例來說，使用者 may have their browser configured to deny permission to persist data for the specified origin.

Example
-------

下列的程式碼片段讀取了目前域名內的 local `Storage` 物件 ，並用`Storage.setItem()` (en-US)，增加一個資料物件 item 到其中

```js
localStorage.setItem("myCat", "Tom");
```

讀取 `localStorage` 內物件的語法如下：

```js
var cat = localStorage.getItem("myCat");
```

移除 `localStorage` 內物件的語法如下：

```js
localStorage.removeItem("myCat");
```

刪除 `localStorage` 內所有物件的語法如下：

```js
// Clear all items
localStorage.clear();
```

**備註：** Please refer to the Using the Web Storage API (en-US) article for a full example.

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

| Specification |
| --- |
| HTML Standard # dom-localstorage-dev |

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

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

See also
--------

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


Window: orientationchange event - Web APIs

Window: orientationchange event
===============================

`orientationchange` 事件在設備方向改變時被觸發。

| 冒泡 | No |
| --- | --- |
| 可取消 | No |
| 介面 | `Event` |
| 事件處理器 | `onorientationchange` |

範例
--

可於 `addEventListener` 方法中使用 `abort` 事件：

```js
window.addEventListener("orientationchange", function () {
  console.log(
    "the orientation of the device is now " + screen.orientation.angle,
  );
});
```

或使用 `onorientationchange` 事件處理器屬性：

```js
window.onorientationchange = function () {
  console.log(
    "the orientation of the device is now " + screen.orientation.angle,
  );
};
```

規範
--

| Specification |
| --- |
| Compatibility Standard # event-orientationchange |

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

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


Window.sessionStorage - Web APIs

Window.sessionStorage
=====================

`sessionStorage` 屬性能讓開發人員訪問當前 origin 的 `Storage` 物件。`sessionStorage` 跟 `localStorage` 很相似：唯一不同的地方是存放在 `localStorage` 的資料並沒有過期的時效；而存放在 `sessionStorage` 的資料則會在頁面 session 結束時清空。只要該頁面頁面(頁籤)沒被關閉或者有還原(restore)該頁面，資料就會保存。**開啟新頁籤或視窗會產生一個新的 sessionStorage**，跟 Session 與 Cookies 的做法不大一樣。

另應該注意：不論資料放在 `sessionStorage` 還是 `localStorage`，都被**限制在該網站的規範內，其他網站無法存取**。

語法
--

```js
// 將資料存到sessionStorage
sessionStorage.setItem("key", "value");

// 從sessionStorage取得之前存的資料
var data = sessionStorage.getItem("key");

// 從sessionStorage移除之前存的資料
sessionStorage.removeItem("key");

// 從sessionStorage移除之前存的所有資料
sessionStorage.clear();
```

### 回傳值

一個 `Storage` 物件.

範例
--

下面簡短的程式碼，訪問了當前域名下的 session `Storage` 物件，並使用 `Storage.setItem()` (en-US) 添加了資料單元。

```js
sessionStorage.setItem("myCat", "Tom");
```

以下提供的範例為將文字輸入元件的內容自動保存，如果瀏覽器不小心重新整理，在頁面恢復後，會自動將內容還原，不會造成尚未送出的資料被清空。

```js
// 取得我們要保留內容的text field元件
var field = document.getElementById("field");

// 檢查是否有之前的autosave的內容
// 這段程式碼會在瀏覽器進入該頁面時被執行
if (sessionStorage.getItem("autosave")) {
  // 還原先前的內容到指定的text field
  field.value = sessionStorage.getItem("autosave");
}

// 註冊事件監聽text field內容的變化
field.addEventListener("change", function () {
  // 並儲存變化後的內容至sessionStorage的物件裡
  sessionStorage.setItem("autosave", field.value);
});
```

**備註：** 完整的範例可參考這篇文章: Using the Web Storage API (en-US)。

規格
--

| Specification |
| --- |
| HTML Standard # dom-sessionstorage-dev |

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

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

相關內容
----

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


window.onpopstate - Web APIs

window.onpopstate
=================

摘要
--

視窗上 popstate 事件的事件處理器。

在同一文件的當前歷史紀錄變動時，如果其變動介於兩個歷史紀錄間，`popstate` 就會被呼叫。如果當前的歷史紀錄是藉由呼叫 `history.pushState()`建立，或曾被 `history.replaceState()` 修改過，`popstate` 事件的 `state` 屬性，將包含一份歷史紀錄的 `state` 物件。

請注意：直接呼叫 `history.pushState()` 或 `history.replaceState()` 不會驅動 `popstate` 事件。`popstate` 事件只會被瀏覽器的行為驅動，例如點擊上一頁按鈕（或透過 JavaScript 呼叫 `history.back()`）。且此事件只會在用戶於同文件的兩個歷史紀錄間瀏覽時作動。

在頁面載入時，不同瀏覽器具有不同的 `popstate` 行為。Chrome 與 Safari 會在頁面載入時觸發 `popstate` 事件，但 Firefox 則不會。

語法
--
```

window.onpopstate = funcRef;
```

* *funcRef* 是一個事件處理函數
popstate 事件
-----------

以下範例，位於 `http://example.com/example.html` 並執行下列程式的頁面，將會產生如標示的對話框：

```js
window.onpopstate = function (event) {
  alert(
    "location: " +
      document.location +
      ", state: " +
      JSON.stringify(event.state),
  );
};

history.pushState({ page: 1 }, "title 1", "?page=1");
history.pushState({ page: 2 }, "title 2", "?page=2");
history.replaceState({ page: 3 }, "title 3", "?page=3");
history.back(); // 跳出 "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // 跳出 "location: http://example.com/example.html, state: null
history.go(2); // 跳出 "location: http://example.com/example.html?page=3, state: {"page":3}
```

請注意，雖然原始的歷史紀錄（`http://example.com/example.html`）沒有關聯的 `state` 物件，在我們第二次呼叫 `history.back()` 時仍然會觸發 `popstate` 事件。

標準
--

* HTML5 popstate event
請參照
---

* `window.history` (en-US)
* Manipulating the browser history
* Ajax navigation example (en-US)


Window.opener - Web APIs

Window.opener
=============

概要
--

回傳一個開啟目前視窗（window）之視窗的參考（reference）。

語法
--
```

objRef = window.opener;
```

範例
--

```js
if (window.opener != indexWin) {
  referToTop(window.opener);
}
```

備註
--

當一個視窗是由另一個視窗所開啟（使用 `Window.open` (en-US) 或一個帶有 `target` (en-US) 屬性設定的連結），被開啟的這個視窗會於 **window.opener** 保留開啟它的第一個視窗之參考。假如目前的視窗沒有開啟它的視窗，則會回傳 NULL。

Windows Phone 瀏覽器不支援 `window.opener`（測試版本為 Microsoft Edge 25.10586.36.0）。若 `window.opener` 為不同的安全區域（security zone），則 IE 也不支援此屬性。

在 某些瀏覽器中，在發起連結的標籤中加入 `rel="noopener"` 屬性，可以阻止設定 `window.opener` 視窗參考。


HTMLElement.click() - Web APIs

HTMLElement.click()
===================

**`HTMLElement.click()`** 方法可以模擬滑鼠點擊一個元素。

當 `click()` 被使用在支援的元素（例如任一 `<input>` (en-US) 元素），便會觸發該元素的點擊事件。事件會冒泡至 document tree（或 event chain）的上層元素，並觸發它們的點擊事件。其中的例外是：`click()` 方法不會讓 `<a>` (en-US) 元素和接收到真實滑鼠點擊一樣進行頁面跳轉。

語法
--
```

elt.click()
```

規範
--

| Specification |
| --- |
| HTML Standard # dom-click-dev |

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

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


HTMLElement.lang - Web APIs

HTMLElement.lang
================

**`HTMLElement.lang`** 屬性（property）可以讀取或設定一個表示元素之語系的標籤屬性（attribute）值。

`HTMLElement.lang` 屬性所回傳的語系代碼定義於網際網路工程任務小組（IETF）的 *Tags for Identifying Languages (BCP47)* 文件中。常見的例子如 "en" 代表英語、"ja" 代表日語、"es" 代表西班牙語等等。此標籤屬性的預設值為 `unknown`。請留意，雖然此標籤屬性於個別層級的元素上是有效的，但大部分都設定於文件的根元素。

`HTMLElement.lang` 屬性只對 `lang` 標籤屬性有作用，而不是 `xml:lang`。

語法
--
```

var languageUsed = elementNodeReference.lang; // Get the value of lang
elementNodeReference.lang = NewLanguage; // Set new value for lang
```

*languageUsed* is a string variable that gets the language in which the text of the current element is written. *NewLanguage* is a string variable with its value setting the language in which the text of the current element is written.

範例
--

```js
// this snippet compares the base language and
// redirects to another url based on language
if (document.documentElement.lang === "en") {
  window.location.href = "Some\_document.html.en";
} else if (document.documentElement.lang === "ru") {
  window.location.href = "Some\_document.html.ru";
}
```

規範
--

| Specification |
| --- |
| HTML Standard # dom-lang |


Node.innerText - Web APIs

Node.innerText
==============

概述
--

**`Node.innerText`** 是一個代表節點及其後代之「已渲染」（rendered）文字內容的屬性。如同一個存取器，`Node.innerText` 近似於使用者利用游標選取成高亮後複製至剪貼簿之元素的內容。此功能最初由 Internet Explorer 提供，並在被所有主要瀏覽器採納之後，於 2016 年正式成為 HTML 標準。

`Node.textContent` (en-US) 屬性是一個相似的選擇，但兩者之間仍有非常不同的差異。

規範
--

| Specification |
| --- |
| HTML Standard # the-innertext-idl-attribute |

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

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

參見
--

* `HTMLElement.outerText` (en-US)
* `Element.innerHTML` (en-US)


製作 WebSocket 客戶端應用程式 - Web APIs

製作 WebSocket 客戶端應用程式
====================

WebSocket 是一種讓瀏覽器與伺服器進行一段互動通訊的技術。使用這項技術的 Webapp 可以直接進行即時通訊而不需要不斷對資料更改進行輪詢（polling）。

**備註：** 當我們的系統架構可以寄存 WebSocket 範例之後，我們會提供聊天／伺服器系統實例的幾個範例。

哪裡有 WebSocket
-------------

若 JavaScript 代碼的範疇是 `Window` (en-US) 物件或是實作 `WorkerUtils` 的物件，則可使用 WebSocket API。也就是可以從 Web Workers 使用 WebSocket。

**備註：** WebSockets API（與底層協定）的開發還在進展中，且目前不同瀏覽器（甚至瀏覽器的不同版本）有很多兼容問題。

建立一個 WebSocket 物件
-----------------

你必須建立一個 `WebSocket` 物件才能讓瀏覽器／伺服器得以以 WebSocket 協定進行通訊，此物件在被建立之後會自動與伺服器連線。

**備註：** 別忘記在 Firefox 6.0 中 `WebSocket` 物件仍有前輟，所以在這裡須改成 `MozWebSocket`。

WebSocket 的建構方法有一個必要參數與一個選擇參數：
```

WebSocket WebSocket(
  in DOMString url,
  in optional DOMString protocols
);

WebSocket WebSocket(
  in DOMString url,
  in optional DOMString[] protocols
);
```

`url`

連線用的 URL，WebSocket 伺服器會回應這個 URL。

根據網際網路工程任務小組（Internet Engineering Task Force，IETF）定義之規範， URL 的協議類型必須是 `ws://` （非加密連線）或是 `wss://` （加密連線）

`protocols` 選擇性

一個表示協定的字串或者是一個表示協定的字串構成的陣列。這些字串可以用來指定子協定，因此一個伺服器可以實作多個 WebSocket 子協定（舉例來說，你可以讓一個伺服器處理不同種類的互動情形，各情形以 `protocol` 分別）。若不指定協定字串則預設值為空字串。

此建構方法可能拋出以下例外：

`SECURITY_ERR`

連線使用的埠被阻擋。

### 範例

此簡單範例建立了一個新的 WebSocket，連到位於 `http://www.example.com/socketserver` 的伺服器。指定的子協定是 "my-custom-protocol"。
```

var mySocket = new WebSocket("ws://www.example.com/socketserver", "my-custom-protocol");
```

回傳之後，`mySocket` 的 `readyState` 會變成 `CONNECTING`。當連線已可以傳輸資料時 `readyState` 會變成 `OPEN`。

要建立一個連線但不指定單一個特定協定，可以指定一個協定構成的陣列：
```

var mySocket = new WebSocket("ws://www.example.com/socketserver", ["protocol1", "protocol2"]);
```

當連線建立的時候（也就是 `readyState` 變成而 `OPEN` 的時候），`protocol` 屬性會回傳伺服器選擇的協定。

傳資料給伺服器
-------

連線開啟之後即可開始傳資料給伺服器。呼叫 `WebSocket` 的 `send()` 來發送訊息：
```

mySocket.send("這是伺服器正迫切需要的文字！");
```

可以被傳送的內容包括字串、`Blob` 或是 `ArrayBuffer`。

**備註：** Firefox 目前只支援字串傳送。

### 用 JSON 傳輸物件

有一個很方便的方法是用 JSON 傳送複雜的資料給伺服器，舉例來說，聊天程式可以設計一種協定，這個協定傳送以 JSON 封裝的資料封包：

```js
// 透過伺服器傳送文字給所有使用者

function sendText() {
  var msg = {
    type: "message",
    text: document.getElementById("text").value,
    id: clientID,
    date: Date.now(),
  };

  mySocket.send(JSON.stringify(msg));
  document.getElementById("text").value = "";
}
```

這份代碼先建立一個物件：`msg`，它包含伺服器處理訊息所需的種種資訊，然後呼叫 `JSON.stringify()` 使該物件轉換成 JSON 格式並呼叫 WebSocket 的 `send()` 方法來傳輸資料至伺服器。

從伺服器接收訊息
--------

WebSockets 是一個事件驅動 API，當瀏覽器收到訊息時，一個「message」事件被傳入 `onmessage` 函數。使用以下方法開始傾聽傳入資料：

```js
mySocket.onmessage = function (e) {
  console.log(e.data);
};
```

### 接收並解讀 JSON 物件

考慮先前在「用 JSON 傳輸物件」談起的聊天應用程式。客戶端可能收到的資料封包有幾種：

* 登入握手
* 訊息文字
* 更新使用者清單

用來解讀傳入訊息的代碼可能像是：

```js
connection.onmessage = function (evt) {
  var f = document.getElementById("chatbox").contentDocument;
  var text = "";
  var msg = JSON.parse(evt.data);
  var time = new Date(msg.date);
  var timeStr = time.toLocaleTimeString();

  switch (msg.type) {
    case "id":
      clientID = msg.id;
      setUsername();
      break;
    case "username":
      text =
        "<b>使用者 <em>" + msg.name + "</em> 登入於 " + timeStr + "</b><br>";
      break;
    case "message":
      text = "(" + timeStr + ") <b>" + msg.name + "</b>: " + msg.text + "<br>";
      break;
    case "rejectusername":
      text =
        "<b>由於你選取的名字已被人使用，你的使用者名稱已被設置為 <em>" +
        msg.name +
        "</em>。";
      break;
    case "userlist":
      var ul = "";
      for (i = 0; i < msg.users.length; i++) {
        ul += msg.users[i] + "<br>";
      }
      document.getElementById("userlistbox").innerHTML = ul;
      break;
  }

  if (text.length) {
    f.write(text);
    document.getElementById("chatbox").contentWindow.scrollByPages(1);
  }
};
```

這裡我們使用 `JSON.parse()` 使 JSON 物件轉換成原來的物件，檢驗並根據內容採取行動。

關閉連線
----

當你想結束 WebSocket 連線的時候，呼叫 WebSocket 的 `close()` 方法：
```

mySocket.close();
```

參考資料
----

IETF: The WebSocket protocol draft-abarth-thewebsocketprotocol-01


Event.defaultPrevented - Web APIs

Event.defaultPrevented
======================

概述
--

回傳一個布林值，表示事件的預設行為是否被取消，也就是事件物件是否曾執行 `preventDefault()` 方法。

**備註：** You should use this instead of the non-standard, deprecated `getPreventDefault()` method (see Firefox bug 691151).

語法
--

```js
bool = event.defaultPrevented;
```

範例
--

```js
if (e.defaultPrevented) {
  /\* the default was prevented \*/
}
```

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-defaultprevented① |

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

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


Event.bubbles - Web APIs

Event.bubbles
=============

### 概述

表示事件是否會向上冒泡傳遞。

### 語法
```

var bool = event.bubbles;
```

回傳一個布林值，若事件會向上冒泡傳遞則回傳 `true`。

### 備註

Only certain events can bubble. Events that do bubble have this property set to `true`. You can use this property to check if an event is allowed to bubble or not.

### 範例

```js
function goInput(e) {
  // checks bubbles and
  if (!e.bubbles) {
    // passes event along if it's not
    passItOn(e);
  }
  // already bubbling
  doOutput(e);
}
```

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-bubbles③ |


Event.currentTarget - Web APIs

Event.currentTarget
===================

`Event` 介面的唯讀屬性 **`currentTarget`** 會標明事件指向（current target）、還有該事件所遍歷的 DOM。屬性總會指向當時處理該事件的事件監聽器所註冊的 DOM 物件，而 `event.target` 屬性則是永遠指向觸發事件的 DOM 物件。

範例
--

`event.currentTarget` 在把相同的事件監聽器，附加到多個元素時，會出現很有趣的事情：

```js
function hide(e) {
  e.currentTarget.style.visibility = "hidden";
  // 在這個函式用於事件監聽器時： this === e.currentTarget
}

var ps = document.getElementsByTagName("p");

for (var i = 0; i < ps.length; i++) {
  ps[i].addEventListener("click", hide, false);
}

// 單擊四周的話 p 元素就會消失
```

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-currenttarget② |

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

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

參見
--

* 事件指向的比較 (en-US)


Event.preventDefault() - Web APIs

Event.preventDefault()
======================

概要
--

如果事件可以被取消，就取消事件（即取消事件的預設行為）。但不會影響事件的傳遞，事件仍會繼續傳遞。

語法
--

```js
event.preventDefault();
```

範例
--

Toggling a checkbox is the default action of clicking on a checkbox. This example demonstrates how to prevent that from happening:

```html
<!doctype html>
<html>
  <head>
    <title>preventDefault example</title>
  </head>

  <body>
    <p>Please click on the checkbox control.</p>
    <form>
      <label for="id-checkbox">Checkbox</label>
      <input type="checkbox" id="id-checkbox" />
    </form>
    <script>
 document.querySelector("#id-checkbox").addEventListener(
 "click",
 function (event) {
 alert("preventDefault will stop you from checking this checkbox!");
 event.preventDefault();
 },
 false,
 );
 </script>
  </body>
</html>
```

You can see `preventDefault` in action here.

The following example demonstrates how invalid text input can be stopped from reaching the input field with preventDefault().
```

<!DOCTYPE html>
<html>
<head>
<title>preventDefault example</title>

<script>
```

```
function Init() {
  var myTextbox = document.getElementById("my-textbox");
  myTextbox.addEventListener("keypress", checkName, false);
}

function checkName(evt) {
  var charCode = evt.charCode;
  if (charCode != 0) {
    if (charCode < 97 || charCode > 122) {
      evt.preventDefault();
      alert(
        "Please use lowercase letters only." +
          "\n" +
          "charCode: " +
          charCode +
          "\n",
      );
    }
  }
}
```

```
</script>
</head>
<body onload="Init ()">
    <p>Please enter your name using lowercase letters only.</p>
    <form>
        <input type="text" id="my-textbox" />
    </form>
</body>
</html>
```

Here is the result of the preceding code:

備註
--

Calling `preventDefault` during any stage of event flow cancels the event, meaning that any default action normally taken by the implementation as a result of the event will not occur.

**備註：** As of Gecko 6.0, calling `preventDefault()` causes the `event.defaultPrevented` property's value to become `true`.

你可以查看 `Event.cancelable` (en-US) 屬性來檢查事件是否能夠被取消。對一個不能被取消的事件呼叫 `preventDefault()` 方法是沒有任何效果的。

`preventDefault()` 方法不會停止事件傳遞。若要停止事件繼續傳遞，可以使用 `Event.stopPropagation()` 方法。

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-preventdefault③ |


Event.target - Web APIs

Event.target
============

指向最初觸發事件的 DOM 物件。與 `event.currentTarget` 屬性不同的是，`event.currentTarget` 屬性總會指向目前於冒泡或捕捉階段正在處理該事件之事件處理器所註冊的 DOM 物件，而 `event.target` 屬性則是永遠指向觸發事件的 DOM 物件。

語法
--
```

theTarget = event.target
```

範例
--

The `event.target` property can be used in order to implement **event delegation**.

```js
// Make a list
var ul = document.createElement("ul");
document.body.appendChild(ul);

var li1 = document.createElement("li");
var li2 = document.createElement("li");
ul.appendChild(li1);
ul.appendChild(li2);

function hide(e) {
  // e.target refers to the clicked <li> element
  // This is different than e.currentTarget which would refer to the parent <ul> in this context
  e.target.style.visibility = "hidden";
}

// Attach the listener to the list
// It will fire when each <li> is clicked
ul.addEventListener("click", hide, false);
```

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-target③ |

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

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

Compatibility notes
-------------------

On IE 6-8 the event model is different. Event listeners are attached with the non-standard `EventTarget.attachEvent` (en-US) method. In this model, the event object has a `Event.srcElement` (en-US) property, instead of the `target` property, and it has the same semantics as `event.target`.

```js
function hide(e) {
  // Support IE6-8
  var target = e.target || e.srcElement;
  target.style.visibility = "hidden";
}
```

參見
--

* Comparison of Event Targets (en-US)


Event.eventPhase - Web APIs

Event.eventPhase
================

表示事件物件目前於事件流（Event Flow）中傳遞的進度為哪一個階段。

語法
--

```js
var phase = event.eventPhase;
```

回傳一個整數值以代表目前事件於事件流中的傳遞階段，可能的值將於事件傳遞階段常數說明。

常數
--

### 事件傳遞階段常數

These values describe which phase the event flow is currently being evaluated.

| 常數 | 值 | 說明 |
| --- | --- | --- |
| `Event.NONE` Read only  | 0 | No event is being processed at this time. |
| `Event.CAPTURING_PHASE` Read only  | 1 | The event is being propagated through the target's ancestor objects. This process starts with the `Window` (en-US), then `Document` (en-US), then the `HTMLHtmlElement` (en-US), and so on through the elements until the target's parent is reached. Event listeners registered for capture mode when `EventTarget.addEventListener()` was called are triggered during this phase. |
| `Event.AT_TARGET` Read only  | 2 | The event has arrived at the event's target. Event listeners registered for this phase are called at this time. If `Event.bubbles` is false, processing the event is finished after this phase is complete. |
| `Event.BUBBLING_PHASE` Read only  | 3 | The event is propagating back up through the target's ancestors in reverse order, starting with the parent, and eventually reaching the containing `Window` (en-US). This is known as bubbling, and occurs only if `Event.bubbles` is `true`. Event listeners registered for this phase are triggered during this process. |

For more details, see section 3.1, Event dispatch and DOM event flow, of the DOM Level 3 Events specification.

範例
--

### HTML

```html
<h4>Event Propagation Chain</h4>
<ul>
  <li>Click 'd1'</li>
  <li>Analyse event propagation chain</li>
  <li>Click next div and repeat the experience</li>
  <li>Change Capturing mode</li>
  <li>Repeat the experience</li>
</ul>
<input type="checkbox" id="chCapture" />
<label for="chCapture">Use Capturing</label>
<div id="d1">
  d1
  <div id="d2">
    d2
    <div id="d3">
      d3
      <div id="d4">d4</div>
    </div>
  </div>
</div>
<div id="divInfo"></div>
```

### CSS

```css
div {
  margin: 20px;
  padding: 4px;
  border: thin black solid;
}

#divInfo {
  margin: 18px;
  padding: 8px;
  background-color: white;
  font-size: 80%;
}
```

### JavaScript

```js
var clear = false,
  divInfo = null,
  divs = null,
  useCapture = false;
window.onload = function () {
  divInfo = document.getElementById("divInfo");
  divs = document.getElementsByTagName("div");
  chCapture = document.getElementById("chCapture");
  chCapture.onclick = function () {
    RemoveListeners();
    AddListeners();
  };
  Clear();
  AddListeners();
};

function RemoveListeners() {
  for (var i = 0; i < divs.length; i++) {
    var d = divs[i];
    if (d.id != "divInfo") {
      d.removeEventListener("click", OnDivClick, true);
      d.removeEventListener("click", OnDivClick, false);
    }
  }
}

function AddListeners() {
  for (var i = 0; i < divs.length; i++) {
    var d = divs[i];
    if (d.id != "divInfo") {
      d.addEventListener("click", OnDivClick, false);
      if (chCapture.checked) d.addEventListener("click", OnDivClick, true);
      d.onmousemove = function () {
        clear = true;
      };
    }
  }
}

function OnDivClick(e) {
  if (clear) {
    Clear();
    clear = false;
  }
  if (e.eventPhase == 2) e.currentTarget.style.backgroundColor = "red";
  var level =
    e.eventPhase == 0
      ? "none"
      : e.eventPhase == 1
        ? "capturing"
        : e.eventPhase == 2
          ? "target"
          : e.eventPhase == 3
            ? "bubbling"
            : "error";
  divInfo.innerHTML += e.currentTarget.id + "; eventPhase: " + level + "<br/>";
}

function Clear() {
  for (var i = 0; i < divs.length; i++) {
    if (divs[i].id != "divInfo")
      divs[i].style.backgroundColor = i & 1 ? "#f6eedb" : "#cceeff";
  }
  divInfo.innerHTML = "";
}
```

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-eventphase③ |


Event.isTrusted - Web APIs

Event.isTrusted
===============

`Event` 介面的 `isTrusted` 唯讀屬性為一個布林值，若事件物件是由使用者操作而產生，則 `isTrusted` 值為 `true`。若事件物件是由程式碼所建立、修改，或是透過 `EventTarget.dispatchEvent()` 來觸發，則 `isTrusted` 值為 `false`。

語法
--
```

var bool = event.isTrusted;
```

範例
--
```

 if (e.isTrusted) {
     /* The event is trusted. */
 } else {
     /* The event is not trusted. */
 }
```

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-istrusted① |

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

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


Event() - Web APIs

Event()
=======

**`Event()`** constructor 能用來建立一個 `事件` 。

語法
--
```

event = new Event(typeArg, eventInit);
```

### 參數

*typeArg*

為一 `DOMString` ，用來表示事件名稱。

*eventInit*選擇性

一個 `EventInit` object，包含以下欄位

| 參數 | 可選 | 默認值 | 類型 | 說明 |
| --- | --- | --- | --- | --- |
| `"bubbles"` | ● | `false` | `Boolean` | 表示該事件是否懸浮（bubble up）。 |
| `"cancelable"` | ● | `false` | `Boolean` | 表示該事件是否已取消（canale）。 |

範例
--

```js
// 建立一個 bubbles up 、並未被取消的事件 「look」 。
var ev = new Event("look", { bubbles: true, cancelable: false });
document.dispatchEvent(ev);
```

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-event |

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

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

參見
--

* `Event`


Event.type - Web APIs

Event.type
==========

**`Event.type`** 唯讀屬性會回傳一個代表此事件物件類型的字串。`Event.type` 屬性是於事件物件建立時被設定，而其屬性值－事件類型名稱也常被當作是特定的事件。

傳至 `EventTarget.addEventListener()` 和 `EventTarget.removeEventListener()` (en-US) 方法中，代表事件類型的參數 *`event`* 是不區分大小寫的。

可用的事件類型，可參考 event reference。

語法
--
```

event.type
```

範例
--

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />

    <title>Event.type Example</title>

    <script>
 var currEvent = null;
 function getEvtType(evt) {
 console.log("//Start------------getEvtType(evt)------------ ");

 currEvent = evt.type;
 console.log(currEvent);

 //document.getElementById("Etype").firstChild.nodeValue = currEvent;
 document.getElementById("Etype").innerHTML = currEvent;

 console.log("//End--------------getEvtType(evt)------------ ");
 }

 //Keyboard events
 document.addEventListener("keypress", getEvtType, false); //[second]

 document.addEventListener("keydown", getEvtType, false); //first
 document.addEventListener("keyup", getEvtType, false); //third

 //Mouse events
 document.addEventListener("click", getEvtType, false); // third

 document.addEventListener("mousedown", getEvtType, false); //first
 document.addEventListener("mouseup", getEvtType, false); //second
 </script>
  </head>

  <body>
    <p>Press any key or click the mouse to get the event type.</p>
    <p>Event type: <span id="Etype" style="color:red">-</span></p>
  </body>
</html>
```

### Result

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-type④ |


Event.timeStamp - Web APIs

Event.timeStamp
===============

說明
--

回傳事件建立的時間（單位是毫秒；從 epoch 開始計算）。

Syntax
------
```

event.timeStamp
```

範例
--
```

var number = event.timeStamp;
```

下面是一個較為完整的範例：

```html
<html>
  <head>
    <title>timeStamp example</title>

    <script type="text/javascript">
 function getTime(event) {
 document.getElementById("time").firstChild.nodeValue = event.timeStamp;
 }
 </script>
  </head>

  <body onkeypress="getTime(event)">
    <p>Press any key to get the current timestamp for the onkeypress event.</p>
    <p>timeStamp: <span id="time">-</span></p>
  </body>
</html>
```

注意
--

這個 property 僅在瀏覽器支持該事件才會有用。

詳細資料
----

* timestamp


Event.stopImmediatePropagation() - Web APIs

Event.stopImmediatePropagation()
================================

除了停止事件繼續捕捉或冒泡傳遞外，也阻止事件被傳入同元素中註冊的其它相同事件類型之監聽器。

語法
--
```

event.stopImmediatePropagation();
```

備註
--

如果一個元素中註冊了多個相同事件類型的監聽器，監聽器將會按照註冊的先後順序被呼叫。在其中任何一個監聽器執行的期間，若是呼叫了事件物件的 `stopImmediatePropagation()` 方法，則接下來尚未執行的監聽器皆不會被呼叫。

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-stopimmediatepropagation① |

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

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


Event.stopPropagation() - Web APIs

Event.stopPropagation()
=======================

`Event` 介面的 **`stopPropagation()`** 方法可阻止當前事件繼續進行捕捉（capturing）及冒泡（bubbling）階段的傳遞。

語法
--
```

event.stopPropagation();
```

範例
--

請參考範例五：事件傳遞 (en-US)章節中關於此方法與 DOM 事件傳遞的更詳細範例。

規範
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-event-stoppropagation① |

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

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

參見
--

* See the DOM specification for the explanation of event flow. (The DOM Level 3 Events draft has an illustration.)
* `Event.preventDefault()` is a related method that prevents the default action of the event from happening.


WebGL tutorial - Web APIs

WebGL tutorial
==============

WebGL 讓網頁內容可以使用一個基於 OpenGL ES 2.0 的 API 以在 HTML `<canvas>`中執行 3D 渲染，且瀏覽器無需使用任何 plug-in。WebGL programs 由 JavaScript 撰寫的指令碼以及透過電腦的 Graphics Processing Unit (GPU)上運行的特殊效果程式碼(shader code)組成。WebGL 元件可與其他 HTML 元件混合，並與該頁的其他部分或該頁背景組合使用。

本教學描述如何使用 `<canvas>` 元件描繪 WebGL 圖像/圖形, 從基礎開始。提供的範例將讓你對於可以用 WebGL 做到什麼有清楚的概念，並提供程式碼片段讓你可以著手建立自己的內容。

開始之前
----

使用`<canvas>` 元件不會非常困難，但你需要有對HTML 與 JavaScript 的基礎認識。`<canvas>` 元件跟 WebGL 在某些舊瀏覽器中不支援，但近來的每個主流瀏覽器都有支援。我們用 JavaScript context object 在 canvas 繪製圖形，這樣圖形就能動態(on the fly)產生。

教學文件
----

WebGL 新手上路

如何建置 WebGL 環境

加入 2D 內容至 WebGL 環境

如何用 WebGL 渲染簡單平面的形狀

使用 shaders 在 WebGL 上色 (en-US)

示範如何使用 shaders 在圖形上上色

WebGL 產生動畫 (en-US)

示範如何旋轉與移動物件以製作簡單的動畫

建立三維物件 (en-US)

示範如何創造並讓 3D 物件(立方體)有動畫

在物件表面貼上材質 (en-US)

示範如何在物件的表面上貼上材質圖

模擬打光 (en-US)

如何在 WebGL 環境模擬打光效果

讓材質產生動畫 (en-US)

如何移動材質圖，在範例中是將 Ogg 影片 貼到一個旋轉中的立方體


WebGL 入門 - Web APIs

WebGL 入門
========

* 次頁 »

WebGL 讓網頁內容能藉由一種基於 OpenGL ES 2.0 的 API 的幫助，於支援此 API 的瀏覽器環境中，不需使用外掛程式就能在 HTML 的 `canvas` 元素中實現二維及三維渲染。 WebGL 程式包含了由 JavaSrcipt 及著色器(GLSL)撰寫的控制碼以及在電腦的圖形處理器( GPU )上執行的特效程式碼(著色器程式碼)。WebGL 元素可以加入其他 HTML 元素之中並與網頁或網頁背景的其他部分混合。

這篇文章將會向你介紹 WebGL 的基礎。這篇文章假設你已經對於三維圖學涉及的數學有所了解，並且它將不會被佯裝為三維圖學的教材。在我們的學習區域內有初學者指南讓你完成編程任務：Learn WebGL for 2D and 3D graphics.

在此教學文件中的程式碼範例都能在 webgl-examples GitHub repository 之中找到。

準備三維渲染
------

首先你需要一個 canvas 元素讓 WebGL 進行渲染。下面的 HTML 定義的 canvas 元素供後續的範例繪製。

```html
<body>
  <canvas id="glCanvas" width="640" height="480"></canvas>
</body>
```

### 準備 WebGL 背景資料

**備註：** 背景資料為 Context 翻譯而來

在下面的 JavaScript 程式碼，當指令完成讀取後會執行 `main()` 函式。目的是為了設定 WebGL 背景資料並且開始渲染內容。

```js
main();

// 從這開始
function main() {
  const canvas = document.querySelector("#glCanvas");
  // 初始化 GL context
  const gl = canvas.getContext("webgl");

  // 當 WebGL 有效才繼續執行
  if (gl === null) {
    alert("無法初始化 WebGL，你的瀏覽器不支援。");
    return;
  }

  // 設定清除色彩為黑色，完全不透明
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  // 透過清除色來清除色彩緩衝區
  gl.clear(gl.COLOR\_BUFFER\_BIT);
}
```

在此我們做的第一件事是取得 canvas 元素的參考，並存入 canvas 變數中。

一旦我們取得了 canvas ，我們透過呼叫 getContext (en-US) 並傳入 `"webgl"` 字串來取得 WebGLRenderingContext (en-US)。若瀏覽器不支援 webgl `getContext` 會回傳 `null` 同時會顯示訊息給使用者並且離開。

如果成功初始化， `gl` 就會成為一個 WebGL 背景資料的參考。在這裡我們設置清除色為黑色，並透過該色清除 context (用背景色重新繪製 canvas )。

至此，你已經有足夠初始化 WebGL 背景資料的程式碼，並且準備好了等待接收內容的容器。

檢視完整程式碼 | 開啟新頁面來檢視結果

亦可參考
----

* An introduction to WebGL: 由 Luz Caballero 撰寫，並出版在 dev.opera.com。 這篇文章點出了 WebGL 的意義，解釋了其運作(包含渲染管路的觀念)，並介紹了一些 WebGL libraries。
* WebGL Fundamentals
* An intro to modern OpenGL: 由 Joe Groff 撰寫的一系列關於 OpenGL 的好文章，提供了 OpenGL 清楚的簡介，從其歷史到重要的圖像管路概念，以及一些展示其原理的範例。如果你完全不懂 OpenGL，這將是一個好的入門介紹。
* 次頁 »


增加一個 2D 物件到 WebGL 環境 - Web APIs

增加一個 2D 物件到 WebGL 環境
====================

* « 前頁
* 次頁 » (en-US)

當你建立了 WebGL 的 context後，便可開始渲染。最簡單的例子就是加入一個普通的正方形。接下來，我們會介紹如何畫一個正方形。

畫場景
---

首先我們需要知道雖然這個範例只是要畫一個正方形，但我們還是在 3D 的空間裡作圖。基本上，我們就是畫一個正方形並把它放在相機前面，使正方形與使用者的視角垂直。我們要定義一個 shader，透過它來渲染我們的物件。接下來，我們會展示如何在螢幕前顯示一個正方形。

### Shader

WebGL Shader 使用 OpenGL ES Shading Language。 這邊不討論 shader 的細節的，但簡而言之，我們需要定義兩個 shader (GPU 上可執行的函數): vertex shader 和 fragment shader。這兩個 shader 會以字串的形式傳入 WebGL，編譯後在 GPU 上執行。

#### Vertex shader

Vertex shader 是用來定義一個變數 gl\_Position 的值來控制畫布空間的值(-1 到+1)，下面的範例，我們設了一個變數`aVertexPosition`用來記錄 vertex 的位置。接下來我們將該位置乘上兩個 4x4 的矩陣(`uProjectionMatrix`和`uModelMatrix`)，並將結果設定為 gl\_Position 的值。如果想要了解更多關於 Projection 和其他矩陣可以參閱這篇文件。

```js
// Vertex shader program

const vsSource = `
 attribute vec4 aVertexPosition;

 uniform mat4 uModelViewMatrix;
 uniform mat4 uProjectionMatrix;

 void main() {
 gl\_Position = uProjectionMatrix \* uModelViewMatrix \* aVertexPosition;
 }
 `;
```

#### Fragment shader

每次 vertex shader 給 gl\_Position 1 到 3 個值的時候，它會分別畫出點、線、三角形。畫圖的時候，會呼叫 fragment shader 來詢問每個 pixel 的顏色。在這個範例中，我們對於每次詢問都回傳白色。

`gl_FragColor` 是 GL 預設的變數用來定義每個 fragment 的顏色，透過設定該變數的值來定義每個 pixel 的顏色，如下：

```js
const fsSource = `
 void main() {
 gl\_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
 }
 `;
```

### 初始化 shader

現在我們已經定義了兩個 shader ，我們接下來要將它們傳入 WebGL，編譯並連結。下面的程式碼呼叫了 loadShader 來建立兩個 shader。接下來，我們要新增一個程式，並將 shader 加入該程式，並將程式連結起來。如果編譯或連接失敗，程式碼會顯示錯誤訊息。

```js
//
// 初始化 shader 來告知WebGL怎麼畫
//
function initShaderProgram(gl, vsSource, fsSource) {
  const vertexShader = loadShader(gl, gl.VERTEX\_SHADER, vsSource);
  const fragmentShader = loadShader(gl, gl.FRAGMENT\_SHADER, fsSource);

  // 建立 shader 程式

  const shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);

  // 錯誤處理

  if (!gl.getProgramParameter(shaderProgram, gl.LINK\_STATUS)) {
    alert(
      "Unable to initialize the shader program: " +
        gl.getProgramInfoLog(shaderProgram),
    );
    return null;
  }

  return shaderProgram;
}

//
// creates a shader of the given type, uploads the source and
// compiles it.
//
function loadShader(gl, type, source) {
  const shader = gl.createShader(type);

  // Send the source to the shader object

  gl.shaderSource(shader, source);

  // Compile the shader program

  gl.compileShader(shader);

  // See if it compiled successfully

  if (!gl.getShaderParameter(shader, gl.COMPILE\_STATUS)) {
    alert(
      "An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader),
    );
    gl.deleteShader(shader);
    return null;
  }

  return shader;
}
```

我們可以透過呼叫 initShaderProgram 來建立 shader 程式

```js
const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
```

接下來我們需要找到 WebGL 生成出的位置。這個例子中我們有一個 attribute、兩個 uniform。 Attributes 從 buffer 獲得值。每次迭代時，vertex shader 從 buffer 得到下一個值並傳入到 attribute。 Uniform 則像是 Javascript 的全域變數。每次迭代，他們的值不會改變。為了之後方便，我們將 shader 程式與 attribute 和 uniform 存放在同一個物件中。

```js
const programInfo = {
  program: shaderProgram,
  attribLocations: {
    vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
  },
  uniformLocations: {
    projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
    modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
  },
};
```

建立正方形平面
-------

在我們渲染前，我們要建立一個 buffer 用來儲存頂點的座標。在此我們宣告一個函數 `initBuffers()` ，隨著之後建立更多複雜的物件，這個動作會重複見到很多次。

```js
function initBuffers(gl) {
  // 建立一個 buffer 來儲存正方形的座標

  const positionBuffer = gl.createBuffer();

  // Select the positionBuffer as the one to apply buffer
  // operations to from here out.

  gl.bindBuffer(gl.ARRAY\_BUFFER, positionBuffer);

  // Now create an array of positions for the square.

  const positions = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0];

  // Now pass the list of positions into WebGL to build the
  // shape. We do this by creating a Float32Array from the
  // JavaScript array, then use it to fill the current buffer.

  gl.bufferData(gl.ARRAY\_BUFFER, new Float32Array(positions), gl.STATIC\_DRAW);

  return {
    position: positionBuffer,
  };
}
```

這個步驟非常簡單，一開始呼叫`gl`物件的函數 `createBuffer()` (en-US) 來產生一個儲存座標的 buffer，並將將該 buffer 綁定 WebGL 的 context。

完成後，我們宣告一個陣列來儲存正方形平面各頂點的座標，並轉型為浮點數陣列並用`bufferData()` (en-US)函數傳入 `gl` 物件。

渲染場景
----

Shader 建立好了、位置也確定好了、正方形平面頂點的位置也已經放到 buffer 後，我們就可以實際來渲染場景了。因為這個例子沒有任何的動畫，`drawScene()`函數非常單純。

```js
function drawScene(gl, programInfo, buffers) {
  gl.clearColor(0.0, 0.0, 0.0, 1.0); // 設定為全黑
  gl.clearDepth(1.0); // 清除所有東西
  gl.enable(gl.DEPTH\_TEST); // Enable 深度測試
  gl.depthFunc(gl.LEQUAL); // Near things obscure far things

  // 開始前先初始化畫布

  gl.clear(gl.COLOR\_BUFFER\_BIT | gl.DEPTH\_BUFFER\_BIT);

  // Create a perspective matrix, a special matrix that is
  // used to simulate the distortion of perspective in a camera.
  // Our field of view is 45 degrees, with a width/height
  // ratio that matches the display size of the canvas
  // and we only want to see objects between 0.1 units
  // and 100 units away from the camera.

  const fieldOfView = (45 \* Math.PI) / 180; // in radians
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const zNear = 0.1;
  const zFar = 100.0;
  const projectionMatrix = mat4.create();

  // note: glmatrix.js always has the first argument
  // as the destination to receive the result.
  mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);

  // Set the drawing position to the "identity" point, which is
  // the center of the scene.
  const modelViewMatrix = mat4.create();

  // Now move the drawing position a bit to where we want to
  // start drawing the square.

  mat4.translate(
    modelViewMatrix, // destination matrix
    modelViewMatrix, // matrix to translate
    [-0.0, 0.0, -6.0],
  ); // amount to translate

  // Tell WebGL how to pull out the positions from the position
  // buffer into the vertexPosition attribute.
  {
    const numComponents = 2; // pull out 2 values per iteration
    const type = gl.FLOAT; // the data in the buffer is 32bit floats
    const normalize = false; // don't normalize
    const stride = 0; // how many bytes to get from one set of values to the next
    // 0 = use type and numComponents above
    const offset = 0; // how many bytes inside the buffer to start from
    gl.bindBuffer(gl.ARRAY\_BUFFER, buffers.position);
    gl.vertexAttribPointer(
      programInfo.attribLocations.vertexPosition,
      numComponents,
      type,
      normalize,
      stride,
      offset,
    );
    gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
  }

  // Tell WebGL to use our program when drawing

  gl.useProgram(programInfo.program);

  // Set the shader uniforms

  gl.uniformMatrix4fv(
    programInfo.uniformLocations.projectionMatrix,
    false,
    projectionMatrix,
  );
  gl.uniformMatrix4fv(
    programInfo.uniformLocations.modelViewMatrix,
    false,
    modelViewMatrix,
  );

  {
    const offset = 0;
    const vertexCount = 4;
    gl.drawArrays(gl.TRIANGLE\_STRIP, offset, vertexCount);
  }
}
```

第一步，我們先將畫布背景設定為黑色，並設定相機的視角。我們將角度設為 45°，並設定成與畫布的長寬比相同。另外我們指定我們只要渲染離相機 0.1 ~ 100 單位遠的物件。

接下來，我們讀入正方形的位置，並把它擺在離相機 6 單位遠的位置。然後我們將正方形頂點的 buffer 綁定到 gl 上。最後我們呼叫`drawArrays()` (en-US)函數來渲染物件。

檢視完整程式碼 | 開啟新頁面來檢視結果

矩陣運算
----

矩陣的運算看起來很複雜，但其實一步一步運算其實不會那麼困難。大部分使用者不會寫自己的運算函數，多半是使用現成的矩陣函數庫，這個例子中我們用的是 glMatrix library 。

可參考以下資料

* Matrices on WebGLFundamentals
* Matrices on Wolfram MathWorld
* Matrix on Wikipedia
* « 前頁
* 次頁 » (en-US)


XMLHttpRequest.setRequestHeader() - Web APIs

XMLHttpRequest.setRequestHeader()
=================================

`XMLHttpRequest` 物件中的 **`setRequestHeader()`** 方法用來設定 HTTP 的表頭請求。當使用 `setRequestHeader()` 的時候，必須在 `open()` (en-US) 之後呼叫，同時也必須在 `send()` (en-US) 之前呼叫。如果這個方法被呼叫了許多次，且設定的表頭是一樣的，那所有設定的值會被合併成一個單一的表頭請求。

在第一次呼叫 `setRequestHeader()` 之後的每一次的呼叫，都會把給定的文字附加在已存在的表頭內容之後。

If no `Accept` header has been set using this, an `Accept` header with the type `"*/*"` is sent with the request when `send()` (en-US) is called.

基於安全的理由，有些表頭只有使用者代理器可以使用。這些表頭包含了： forbidden header names (en-US) 和 forbidden response header names (en-US).

**備註：** For your custom fields, you may encounter a "**not allowed by Access-Control-Allow-Headers in preflight response**" exception when you send requests across domains. In this situation, you need to set up the `Access-Control-Allow-Headers` (en-US) in your response header at server side.

語法
--
```

XMLHttpRequest.setRequestHeader(header, value)
```

### 參數

`header`

想要設定所屬值的表頭名稱。

`value`

用來設定表頭本身的值。

### 回傳值

未定義。

規範
--

| Specification |
| --- |
| XMLHttpRequest Standard # the-setrequestheader()-method |

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

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

參見
--

* 使用 XMLHttpRequest
* HTML in XMLHttpRequest (en-US)


XMLHttpRequest.status - Web APIs

XMLHttpRequest.status
=====================

**XMLHttpRequest.status** 屬性根據 XMLHttpRequest 的回應傳回數值化的狀況編碼。狀況編碼為一正短整數（`unsigned short）。`Before the request is complete, the value of `status` will be `0`. It is worth noting that browsers report a status of 0 in case of XMLHttpRequest errors too.

The status codes returned are the standard HTTP status codes. For example, `status` `200` denotes a successful request. If the server response doesn't explicitly specify a status code, `XMLHttpRequest.status` will assume the default value of `200`.

Example
-------

```js
var xhr = new XMLHttpRequest();
console.log("UNSENT", xhr.status);

xhr.open("GET", "/server", true);
console.log("OPENED", xhr.status);

xhr.onprogress = function () {
  console.log("LOADING", xhr.status);
};

xhr.onload = function () {
  console.log("DONE", xhr.status);
};

xhr.send(null);

/\*\*
 \* Outputs the following:
 \*
 \* UNSENT 0
 \* OPENED 0
 \* LOADING 200
 \* DONE 200
 \*/
```

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

| Specification |
| --- |
| XMLHttpRequest Standard # the-status-attribute |

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

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

See also
--------

* List of HTTP response codes


XMLHttpRequest() - Web APIs

XMLHttpRequest()
================

**`XMLHttpRequest()`** 建構式會建立一個新的 `XMLHttpRequest` 物件。

關於如何使用 `XMLHttpRequest` 物件的細節，請參照：使用 XMLHttpRequest。

語法
--

```js
const request = new XMLHttpRequest();
```

### 參數

無。

### 回傳值

將回傳一個新的 `XMLHttpRequest` 物件。`XMLHttpRequest` 物件在呼叫`send()` (en-US) 送出要求到伺服器之前，至少要藉著呼叫 `open()` (en-US) 來準備好必需的設定。

非標準的 Firefox 語法
---------------

Firefox 16 added a non-standard parameter to the constructor that can enable anonymous mode (see Firefox bug 692677). Setting the `mozAnon` flag to `true` effectively resembles the `AnonXMLHttpRequest()` constructor described in older versions of the XMLHttpRequest specification.

```js
const request = new XMLHttpRequest(paramsDictionary);
```

### Parameters (non-standard)

`objParameters`

There are two flags you can set:

`mozAnon`

Boolean: Setting this flag to `true` will cause the browser not to expose the origin (en-US) and user credentials when fetching resources. Most important, this means that cookies will not be sent unless explicitly added using setRequestHeader.

`mozSystem`

Boolean: Setting this flag to `true` allows making cross-site connections without requiring the server to opt-in using CORS. *Requires setting `mozAnon: true`, i.e. this can't be combined with sending cookies or other user credentials. This only works in privileged (reviewed) apps (Firefox bug 692677); it does not work on arbitrary webpages loaded in Firefox*

參見
--

* 使用 XMLHttpRequest
* HTML in XMLHttpRequest (en-US)


XMLHttpRequest.withCredentials - Web APIs

XMLHttpRequest.withCredentials
==============================

**`XMLHttpRequest.withCredentials`** 屬性是一個 `Boolean` 型別，它指出無論是否使用 `Access-Control` 標頭在跨站的要求上，都應該使用像 Cookies、Authorization 標頭或 TLS 用戶端憑證來進行驗證。在相同來源的要求設定 `withCredentials` 沒有任何效果。

In addition, this flag is also used to indicate when cookies are to be ignored in the response. The default is `false`. `XMLHttpRequest` from a different domain cannot set cookie values for their own domain unless `withCredentials` is set to `true` before making the request. The third-party cookies obtained by setting `withCredentials` to true will still honor same-origin policy and hence can not be accessed by the requesting script through document.cookie (en-US) or from response headers.

**備註：** 永遠不會影響到同源請求。

**備註：** `XMLHttpRequest` responses from a different domain *cannot* set cookie values for their own domain unless `withCredentials` is set to `true` before making the request, regardless of `Access-Control-` header values.

範例
--

```js
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com/", true);
xhr.withCredentials = true;
xhr.send(null);
```

規格
--

| Specification |
| --- |
| XMLHttpRequest Standard # the-withcredentials-attribute |

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

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


XMLHttpRequest.readyState - Web APIs

XMLHttpRequest.readyState
=========================

**XMLHttpRequest.readyState** 屬性會回傳一個 XMLHttpRequest 客戶端物件目前的狀態。一個 XHR 客戶端可以為下列其中一種狀態：

| 值 | 狀態 | 說明 |
| --- | --- | --- |
| `0` | `UNSENT` | 客戶端已被建立，但 `open()` 方法尚未被呼叫。 |
| `1` | `OPENED` | `open()` 方法已被呼叫。 |
| `2` | `HEADERS_RECEIVED` | `send()` 方法已被呼叫，而且可取得 header 與狀態。 |
| `3` | `LOADING` | 回應資料下載中，此時 `responseText` 會擁有部分資料。 |
| `4` | `DONE` | 完成下載操作。 |

UNSENT

XMLHttpRequest 客戶端物件已被建立，但 open() 方法尚未被呼叫。

OPENED

open() 方法已被呼叫。於此狀態時，可以使用 setRequestHeader() 方法設定請求標頭（request headers），並可呼叫 send() (en-US) 方法來發送請求。

HEADERS\_RECEIVED

send() 方法已被呼叫，並且已接收到回應標頭（response header）。

LOADING

正在接收回應內容（response's body）。如 `responseType` (en-US) 屬性為 "text" 或空字串，則 `responseText` (en-US) 屬性將會在載入的過程中擁有已載入部分之回應（response）內容中的文字。

DONE

請求操作已完成。這意味著資料傳輸可能已成功完成或是已失敗。

**備註：** 這些狀態名稱在 Internet Explorer 中略有不同。其中 `UNSENT`, `OPENED`, `HEADERS_RECEIVED`, `LOADING` 和 `DONE` 變成了 `READYSTATE_UNINITIALIZED` (0), `READYSTATE_LOADING` (1), `READYSTATE_LOADED` (2), `READYSTATE_INTERACTIVE` (3) 和`READYSTATE_COMPLETE` (4)。

範例
--

```js
var xhr = new XMLHttpRequest();
console.log("UNSENT", xhr.readyState); // readyState will be 0

xhr.open("GET", "/api", true);
console.log("OPENED", xhr.readyState); // readyState will be 1

xhr.onprogress = function () {
  console.log("LOADING", xhr.readyState); // readyState will be 3
};

xhr.onload = function () {
  console.log("DONE", xhr.readyState); // readyState will be 4
};

xhr.send(null);
```

規範
--

| Specification |
| --- |
| XMLHttpRequest Standard # states |

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

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


怪異模式與標準模式 - HTML：超文本標記語言

怪異模式與標準模式
=========

很久以前，網頁通常有兩種版本：針對網景（Netscape）的 Navigator 的版本，以及針對微軟（Microsoft）的 Internet Explorer 的版本。在 W3C 創立網路標準後，為了不破壞當時既有的網站，瀏覽器不能直接起用這些標準。因此，瀏覽器導入了能分辨符合新規範、或屬於老舊網站的兩種模式。

目前瀏覽器的排版引擎有三種模式：怪異模式（Quirks mode）、接近標準模式（Almost standards mode）、以及標準模式（Standards mode）。在**怪異模式**，排版會模擬 Navigator 4 與 Internet Explorer 5 的非標準行為。為了支持在網路標準被廣泛採用前，就已經建置好的網站，這麼做是必要的。在**標準模式**，行為（期待）由 HTML 與 CSS 的規範描述起來。在**接近標準模式**，有少數的怪異行為被實行。

瀏覽器如何決定用哪個模式？
-------------

對 HTML 文件來說，瀏覽器使用文件開頭的 DOCTYPE 來決定用怪異模式處理或標準模式處理。為了確保頁面使用標準模式，請確認你的頁面，如同本範例一樣擁有 DOCTYPE：

```html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>
  </head>
  <body></body>
</html>
```

範例中的 `<!DOCTYPE html>` 是所有可用之中最簡單、並由 HTML5 推薦的。HTML 的早期變種也屬於推薦標準，不過今日的瀏覽器都會對這個 DOCTYPE 使用標準模式，就算是已過時的 Internet Explorer 6 也一樣。目前並沒有正當理由，去使用其他更複雜的 DOCTYPE。如果使用其他 DOCTYPE，可能會冒著觸發接近標準模式、或著怪異模式的風險。

請確定把 DOCTYPE 正確地放在 HTML 文件頂端。任何放在 DOCTYPE 前面的東西，如註解或 XML 聲明，會令 Internet Explorer 9 或更早期的瀏覽器觸發怪異模式。

在 HTML5，DOCTYPE 唯一的作用是啟用標準模式。更早期的 HTML 標準會附加其他意義，但沒有任何瀏覽器會用 DOCTYPE 去做模式間互換以外的用途。

另請參閱不同的瀏覽器選擇不同模式的詳細說明。

### XHTML

如果你的網頁使用 XHTML 並在 `Content-Type` HTTP 標頭使用 `application/xhtml+xml` MIME 類型，你不需要使用 DOCTYPE 啟動標準模式，因為這種文件會永遠使用標準模式。不過請注意服務頁面使用 `application/xhtml+xml` 會令 Internet Explorer 8 出於未知格式之故出現下載對話框，支持 XHTML 的第一個 Internet Explorer 版本是 Internet Explorer 9。

如果你的類 XHTML 網頁使用 `text/html` MIME 類型，瀏覽器會視為 HTML，你就需要 DOCTYPE 啟用標準模式。

我要如何知道目前是哪個模式？
--------------

在 Firefox，請從右鍵選單選擇*觀看頁面資訊*，然後查看*繪製模式*。

在 Internet Explorer，請按下 *F12*，然後查看*文件模式*.

這些模式有何不同？
---------

請參閱怪異模式的清單還有接近標準模式的清單之間的差別。


HTML 參考 - HTML：超文本標記語言

HTML 參考
=======

這裡的 HTML 參考描述了所有 HTML 的**元素**（elements）與**屬性**（attributes），包括為所有元素接受的**全域屬性**（global attributes）。

HTML 元素指引 (en-US)

本頁列出了所有 HTML elements

HTML 屬性指引

HTML 中的元素具有屬性 ; 而這些屬性可以藉由各種方式去設定元素或調整它們的行為，以符合使用者的期待。

全域屬性 (en-US)

Global attributes may be specified on all HTML elements, even those not specified in the standard. That means that any non-standard elements must still permit these attributes, even though using those elements means that the document is no longer HTML5-compliant. For example, HTML5-compliant browsers hide content marked as <foo hidden>...<foo>, even though <foo> is not a valid HTML element.

連結類型

In HTML, the following link types indicate the relationship between two documents, in which one links to the other using an <a>, <area>, or <link> element.


HTML attribute reference - HTML：超文本標記語言

HTML attribute reference
========================

HTML 中的元素具有**屬性**；而這些屬性可以藉由各種方式去設定元素或調整它們的行為，以符合使用者的期待。

屬性列表
----

| 屬性名稱 | 元素 | 描述 |
| --- | --- | --- |
| `hidden` | Global attribute | 避免呈現給定的元素，並且保持子元素，例如 script elements、active。 |
| `high` | `<meter>` (en-US) | 指示下界的上限範圍。 |
| `href` | `<a>` (en-US)、`<area>` (en-US)、`<base>` (en-US)、`<link>` (en-US) | 連結資源的 URL。 |
| `hreflang` | `<a>` (en-US)、`<area>` (en-US)、`<link>` (en-US) | 指定連結資源的語言。 |
| `http-equiv` | `<meta>` (en-US) |  |
| `icon` | `<command>` | 指定呈現指令的圖片。 |
| `id` | Global attribute | 經常和 CSS 一起被用來設計特定元素。這個屬性的值必須是唯一的。 |
| `ismap` | `<img>` (en-US) | 指示該圖像是伺服器端之影像地圖的一部分。 |
| `itemprop` | Global attribute |  |
| `kind` | `<track>` (en-US) | 指明文章 track 的類型。 |
| `label` | `<track>` (en-US) | 指明文章 track 的使用者可讀之標題。 |
| `lang` | Global attribute | 定義該元素中所使用的語言。 |
| `language` | `<script>` | 定義該元素中所使用的腳本語言。 |
| `list` | `<input>` (en-US) | 指示一串預先定義的選項供使用者參考。 |
| `loop` | `<audio>` (en-US)、`<marquee>`、`<video>` (en-US) | 指示當媒體完成時，是否應該從一開始的時候播放。 |
| `low` | `<meter>` (en-US) | 指示上界的下限範圍。 |
| `manifest` | `<html>` (en-US) | 指定文件中緩存清單的 URL。 |
| `max` | `<input>` (en-US)、`<meter>` (en-US)、`<progress>` (en-US) | 指示所允許的最大值。 |
| `maxlength` | `<input>` (en-US)、`<textarea>` (en-US) | 定義該元素中所允許的最大字元數目。 |
| `media` | `<a>` (en-US)、`<area>` (en-US)、`<link>` (en-US)、`<source>` (en-US)、`<style>` (en-US) | 指定一些連接資源已經被設計的媒體。 |
| `method` | `<form>` (en-US) | 定義當呈交該格式時，哪個 HTTP 方法要被使用。可以用 GET（預設）或是 POST。 |
| `min` | `<input>` (en-US)、`<meter>` (en-US) | 指示所允許的最小值。 |
| `multiple` | `<input>` (en-US)、`<select>` (en-US) | 指示多個值是否可以進入單一輸入的 `email` 或是 `file` 之類別。 |
| `name` | `<button>` (en-US)、`<form>` (en-US)、`<fieldset>` (en-US)、`<iframe>` (en-US)、`<input>` (en-US)、`<object>` (en-US)、`<output>` (en-US)、`<select>` (en-US)、`<textarea>` (en-US)、`<map>` (en-US)、`<meta>` (en-US)、`<param>` (en-US) | 元素的名字。例如被伺服器所使用時，來識別格式提交的現場。 |
| `novalidate` | `<form>` (en-US) | 該屬性指示當本格式被提交時，並無法通過驗證。 |
| `open` | `<details>` (en-US) | 指示是否細節顯示於加載頁面上。 |
| `optimum` | `<meter>` (en-US) | 指示最佳化數值。 |
| `pattern` | `<input>` (en-US) | 定義一個元素值將被驗證的正規表達式。 |
| `ping` | `<a>` (en-US)、`<area>` (en-US) |  |
| `placeholder` | `<input>` (en-US)、`<textarea>` (en-US) | 提示使用者什麼可以被輸入進該區。 |
| `poster` | `<video>` (en-US) | 顯現一個指示 poster frame 的 URL，直到使用者撥放或是搜索。 |
| `preload` | `<audio>` (en-US)、`<video>` (en-US) | 指示是否整個資源、一部分的資源、或是沒有資源應該被預先裝載。 |
| `pubdate` | `<time>` | 指示該日期和時間，是否和距離最近的 `<article>` (en-US) 舊元素的日期一樣。 |
| `radiogroup` | `<command>` |  |
| `readonly` | `<input>` (en-US)、`<textarea>` (en-US) | 指示是否該元素可以被編輯。 |
| `rel` | `<a>` (en-US)、`<area>` (en-US)、`<link>` (en-US) | 指定目標物件和連結物驗的關係。 |
| `required` | `<input>` (en-US)、`<select>` (en-US)、`<textarea>` (en-US) | 指示該元素是否被要求填寫。 |
| `reversed` | `<ol>` (en-US) | 指示該目錄是否應以降序展出而不是升序。 |
| `rows` | `<textarea>` (en-US) | 定義 textarea 的行數。 |
| `rowspan` | `<td>` (en-US)、`<th>` (en-US) | 定義表格單元的行數應該被 span over。 |
| `sandbox` | `<iframe>` (en-US) |  |
| `spellcheck` | Global attribute | 指示為該元素的拼字檢查是否允許。 |
| `scope` | `<th>` (en-US) |  |
| `scoped` | `<style>` (en-US) |  |
| `seamless` | `<iframe>` (en-US) |  |
| `selected` | `<option>` (en-US) | 定義一個值將被選擇到上載頁面中。 |
| `shape` | `<a>` (en-US)、`<area>` (en-US) |  |
| `size` | `<input>` (en-US)、`<select>` (en-US) | 定義元素的寬度 (以 pixel 為單位) 。如果該元素之類型的屬性是文本或是密碼，那麼它就是字元的數目。 |
| `sizes` | `<link>` (en-US) |  |
| `span` | `<col>` (en-US)、`<colgroup>` (en-US) |  |
| `src` | `<audio>` (en-US)、`<embed>` (en-US)、`<iframe>` (en-US)、`<img>` (en-US)、`<input>` (en-US)、`<script>`、`<source>` (en-US)、`<track>` (en-US)、`<video>` (en-US) | 可嵌入內容的網址。 |
| `srcdoc` | `<iframe>` (en-US) |  |
| `srclang` | `<track>` (en-US) |  |
| `srcset` | `<img>` (en-US) |  |
| `start` | `<ol>` (en-US) | 如果第一個數字不是 1 的話，則定義該數。 |
| `step` | `<input>` (en-US) |  |
| `style` | Global attribute | 定義多載先前的樣式設定之 CSS 樣式。 |
| `summary` | `<table>` |  |
| `tabindex` | Global attribute | 多載瀏覽器的預設頁面標籤之順序並且遵守指定的那個。 |
| `target` | `<a>` (en-US)、`<area>` (en-US)、`<base>` (en-US)、`<form>` (en-US) |  |
| `title` | Global attribute | 當滑鼠標停在元素時，文本會顯示在工具提示中。 |
| `type` | `<button>` (en-US)、`<input>` (en-US)、`<command>`、`<embed>` (en-US)、`<object>` (en-US)、`<script>`、`<source>` (en-US)、`<style>` (en-US)、`<menu>` (en-US) | 定義元素的類型。 |
| `usemap` | `<img>` (en-US)、`<input>` (en-US)、`<object>` (en-US) |  |
| `value` | `<button>` (en-US)、`<option>` (en-US)、`<input>` (en-US)、`<li>` (en-US)、`<meter>` (en-US)、`<progress>` (en-US)、`<param>` (en-US) | 定義將顯示在加載頁面上元素的預設值。 |
| `width` | `<canvas>`、`<embed>` (en-US)、`<iframe>` (en-US)、`<img>` (en-US)、`<input>` (en-US)、`<object>` (en-US)、`<video>` (en-US) | 注意 : 在有些情況中，例如 `<div>`，這是傳統的屬性，而 CSS `width` 特性應當被使用。在其他的情況中，例如 `<canvas>` ，寬度必須用該屬性來指定。 |
| `wrap` | `<textarea>` (en-US) | 指定文章是否要被掩飾。 |
| `border` | `<img>` (en-US)、`<object>` (en-US)、`<table>` | 邊界寬度。注意：這是一個傳統的屬性。請利用 CSS `border` (en-US) 特性。 |
| `buffered` | `<audio>` (en-US)、`<video>` (en-US) | 包含被緩衝之媒體的時間範圍。 |
| `charset` | `<meta>` (en-US)、`<script>` | 聲明頁面或腳本的字元編碼。 |
| `checked` | `<command>`、`<input>` (en-US) | 指定在加載頁面上的元素是否要被檢查。 |
| `cite` | `<blockquote>`、`<del>` (en-US)、`<ins>` (en-US)、`<q>` | 包含一個 URL，用來指出引用或是改變的來源地址。 |
| `class` | Global attribute | 經常使用共同屬性和 CSS 一起設計元素。 |
| `code` | `<applet>` | 指明被加載與執行的 applet 類別文件之 URL。 |
| `codebase` | `<applet>` | This attribute gives the absolute or relative URL of the directory where applets' .class files referenced by the code attribute are stored. |
| `color` | `<basefont>` (en-US)、`<font>`、`<hr>` | 該屬性使用命名顏色或十六進制 #RRGGBB 格式來設置文本顏色。注意：這是一個傳統的屬性。請使用 CSS `color` (en-US) 特性。 |
| `cols` | `<textarea>` (en-US) | 定義在一個 textarea 中有多少欄位。 |
| `colspan` | `<td>` (en-US)、`<th>` (en-US) | colspan 屬性定義一個單元格之欄位的數量。 |
| `content` | `<meta>` (en-US) | 一個有關於 `http-equiv` 或是根據上下文 `name` 的值 。 |
| `contenteditable` | Global attribute | 指定元素的內容是否可以被編輯。 |
| `contextmenu` | Global attribute | 定義將作為元素上下文選項單的 `<menu>` (en-US) 元素之 ID。 |
| `controls` | `<audio>` (en-US)、`<video>` (en-US) | 指定瀏覽器是否應該顯示錄放控制給使用者。 |
| `coords` | `<area>` (en-US) | 一組值指明熱點區域的座標。 |
| `data` | `<object>` (en-US) | 指明 URL 的資源。 |
| `data-*` | Global attribute | 讓你可以將自行定義屬性附加在 HTML 元素上。 |
| `datetime` | `<del>` (en-US)、`<ins>` (en-US)、`<time>` | 指定元素所相關的日期與時間。 |
| `default` | `<track>` (en-US) | 指定 track 應被啟用，除非使用者的偏好表示不同。 |
| `defer` | `<script>` | 指定該頁面被瀏覽完後腳本應被執行。 |
| `dir` | Global attribute | 定義文章的方向。被允許的值有 ltr (Left-To-Right) 或 rtl (Right-To-Left)。 |
| `dirname` | `<input>` (en-US)、`<textarea>` (en-US) |  |
| `disabled` | `<button>` (en-US)、`<command>`、`<fieldset>` (en-US)、`<input>` (en-US)、`<optgroup>` (en-US)、`<option>` (en-US)、`<select>` (en-US)、`<textarea>` (en-US) | 指名使用者是否可以與元素互動。 |
| `download` | `<a>` (en-US)、`<area>` (en-US) | 指定該超連結是用於下載的資源。 |
| `draggable` | Global attribute | 定義元素是否可以拖曳。 |
| `dropzone` | Global attribute | 指定該元素接受它內容的滑鼠落下物。 |
| `enctype` | `<form>` (en-US) | 當方法為 POST 的時候，定義格式日期的內容類型。 |
| `for` | `<label>` (en-US)、`<output>` (en-US) | 描述屬於這一個的元素。 |
| `form` | `<button>` (en-US)、`<fieldset>` (en-US)、`<input>` (en-US)、`<label>` (en-US)、`<meter>` (en-US)、`<object>` (en-US)、`<output>` (en-US)、`<progress>` (en-US)、`<select>` (en-US)、`<textarea>` (en-US) | 指定元素之所有者的格式。 |
| `formaction` | `<input>` (en-US)、`<button>` (en-US) | 指定元素的作用，多載的動作被定義在 `<form>` (en-US)。 |
| `headers` | `<td>` (en-US)、`<th>` (en-US) | 對適用於該元素的 | 元素之 ID。 |
| `height` | `<canvas>`、`<embed>` (en-US)、`<iframe>` (en-US)、`<img>` (en-US)、`<input>` (en-US)、`<object>` (en-US)、`<video>` (en-US) | 注意：在有些情況中，例如 `<div>`，這是傳統的屬性，而 CSS `height` 特性應當被使用。在其他的情況中，例如 `<canvas>`，高度必須用該屬性來指定。 |
| `accept` | `<form>` (en-US)、`<input>` (en-US) | 伺服器接受的類型之列表，通常是文件類型。 |
| `accept-charset` | `<form>` (en-US) | 支持字元集的列表。 |
| `accesskey` | Global attribute | 定義鍵盤快捷鍵來啟動或添加焦點到該元素。 |
| `action` | `<form>` (en-US) | 一個程序處理經由該格式提交信息的 URI。 |
| `align` | `<applet>`、`<caption>` (en-US)、`<col>` (en-US)、`<colgroup>` (en-US)、`<hr>`、`<iframe>` (en-US)、`<img>` (en-US)、`<table>`、`<tbody>` (en-US)、`<td>` (en-US)、`<tfoot>` (en-US) 、`<th>` (en-US)、`<thead>` (en-US)、`<tr>` (en-US) | 指定元素的水平對齊方式。 |
| `alt` | `<applet>`、`<area>` (en-US)、`<img>` (en-US)、`<input>` (en-US) | 在圖像無法顯示的情況下，顯示代替文本。 |
| `async` | `<script>` | 指定該腳本應該被不同步得執行。 |
| `autocomplete` | `<form>` (en-US)、`<input>` (en-US) | 指定是否以該格式控制，可以在默認情況下由瀏覽器自動完成其值。 |
| `autofocus` | `<button>` (en-US)、`<input>` (en-US)、`<select>` (en-US)、`<textarea>` (en-US) | 該元素應該在頁面加載後自動焦距。 |
| `autoplay` | `<audio>` (en-US)、`<video>` (en-US) | 音頻或視頻應該越早撥放越好。 |
| `autosave` | `<input>` (en-US) | 上一個值應該持續存在到跨頁面加載的可選值之下拉列表中。 |
| `bgcolor` | `<body>` (en-US)、`<col>` (en-US)、`<colgroup>` (en-US)、`<marquee>`、`<table>`、`<tbody>` (en-US)、`<tfoot>` (en-US)、`<td>` (en-US)、`<th>` (en-US)、`<tr>` (en-US) | 元素的背景顏色。注意：這是一個傳統的屬性。請使用 CSS `background-color` 特性。 |

內容與 IDL 屬性
----------

在 HTML 中，大部分的屬性有兩種面向：**內容屬性**與 **IDL 屬性**。

內容屬性是你可以從內容中設定的屬性 (HTML 程式碼) 而且你可以藉由 `element.setAttribute()` (en-US) 或是 `element.getAttribute()` (en-US) 來設定它或得到它。內容屬性永遠都是字串，即便我們所期望的值是一個整數。舉例來說，假設今天要用內容屬性去設定一個 `<input>` (en-US) 元素的最大長度是 42，你必須在該元素上呼叫 setAttribute("maxlength", "42")。

IDL 屬性也被稱為 JavaScript 特性。你可以使用 JavaScript 特性的 element.foo 以閱讀或是設定這些屬性。當你要得到 IDL 屬性時，它總是要使用 (但可能改變) 基本的內容屬性以返回值，而當你要設定 IDL 屬性時，它需要儲存資料在內容屬性中。換句話說，IDL 屬性在本質上反映了內容屬性。

在大部分的時間中，當 IDL 屬性真正被使用時，將會返回它們的值。舉例而言，`<input>` (en-US) 元素的預設型態是 "text"，所以如果你設定 input.type="foobar"，<input> 元素一樣是 text 的型態 (在外觀和行為上而言)，但是 "type" 內容屬性的值將會變成 "foobar"。然而，IDL 屬性的型態將會回傳 "text" 字串。

IDL 屬性並非永遠的字串 ; 舉例來說，input.maxlength 便是一個數字(型態為 signed long)。當使用 IDL 屬性，你會閱讀或是設定所需的型態，而當你設定 input.maxlength 時，它總是回傳一個數字，因為它正需要一個數字。如果你傳入別的型態，它會依照標準 JavaScript 型態轉換規則，將傳入值轉成一個數字。

IDL 屬性可以 反應其他型態，例如 unsigned long、URLs、booleans，等等。不幸的是，並沒有明確的規則來規範，而且與 IDL 屬性行為相對應的內容屬性連結中，也沒有取決於該屬性的方式。在大部分的時間裡，它會遵守 規範中所制定的規則，但有時候它並不會。HTML 規範嘗試讓它變得容易使用，但由於各種原因 (大多是因為歷史)，有些屬性表現得很奇怪 (舉例來說，select.size)，而你應該詳細閱讀規範以了解各個屬性的行為。

另請參見
----

* HTML 元素 (en-US)


內容類型 - HTML：超文本標記語言

內容類型
====

每個 HTML 元素都要遵從該元素可擁有何種內容規則，這些規則被歸為幾種常用的內容模型（content model）。每個 HTML 元素都屬於零個、一個、或數個內容的模型，所有元素內容的設置規則都要遵從 HTML 一致性文件。

內容類型有三種類型：

* 主要內容類型（Main content categories）描述了許多元素共享的常見內容規則（content rule）。
* 表單相關內容類型（Form-related content categories）描述了表單相關元素的內容規則。
* 特別內容類型（Specific content categories） 描述了只有少數元素共享的內容規則，有時甚至只有特定上下文。

![Content_categories_venn.png](/zh-TW/docs/Web/HTML/Content_categories/content_categories_venn.png)

主要內容類型
------

### 資訊元內容（Metadata content）

屬於*元資訊內容*類型的元素修飾該文件其餘部分的陳述或行為、與其他文件建立連結、或是傳達其他*外來*（out of band）訊息。

屬於這個類型的元素有 `<base>` (en-US)、
已棄用
`<command>`、`<link>` (en-US)、`<meta>` (en-US)、`<noscript>`、`<script>`、`<style>` (en-US) 與 `<title>`

### 流內容（Flow content）

屬於流內容的元素通常含有文字或嵌入內容。它們是：`<a>` (en-US)、`<abbr>` (en-US)、`<address>` (en-US)、`<article>` (en-US)、`<aside>` (en-US)、`<audio>` (en-US)、`<b>` (en-US),`<bdo>` (en-US)、`<bdi>` (en-US)、`<blockquote>`、`<br>`、`<button>` (en-US)、`<canvas>`、`<cite>` (en-US)、`<code>`、
已棄用
`<command>`、`<data>` (en-US)、`<datalist>` (en-US)、`<del>` (en-US)、`<details>` (en-US)、`<dfn>` (en-US)、`<div>`、`<dl>` (en-US)、`<em>` (en-US)、`<embed>` (en-US)、`<fieldset>` (en-US)、`<figure>` (en-US)、`<footer>` (en-US)、`<form>` (en-US)、`<h1>` (en-US)、`<h2>` (en-US)、`<h3>` (en-US)、`<h4>` (en-US)、`<h5>` (en-US)、`<h6>` (en-US)、`<header>` (en-US)、`<hgroup>` (en-US)、`<hr>`、`<i>` (en-US)、`<iframe>` (en-US)、`<img>` (en-US)、`<input>` (en-US)、`<ins>` (en-US)、`<kbd>` (en-US)、`<label>` (en-US)、`<main>` (en-US)、`<map>` (en-US)、`<mark>` (en-US)、`<math> (en-US)`、`<menu>` (en-US)、`<meter>` (en-US)、`<nav>`、`<noscript>`、`<object>` (en-US)、`<ol>` (en-US)、`<output>` (en-US)、`<p>` (en-US)、`<pre>` (en-US)、`<progress>` (en-US)、`<q>`、`<ruby>`、`<s>` (en-US)、`<samp>` (en-US)、`<script>`、`<section>` (en-US)、`<select>` (en-US)、`<small>` (en-US)、`<span>` (en-US)、`<strong>` (en-US)、`<sub>` (en-US)、`<sup>` (en-US)、`<svg>` (en-US)、`<table>`、`<template>`、`<textarea>` (en-US)、`<time>`、`<ul>` (en-US)、`<var>` (en-US)、`<video>` (en-US)、`<wbr>` (en-US) 還有文字。

在滿足特定條件下，某些元素也屬這個類型：

* `<area>` (en-US)，如果它是 `<map>` (en-US) 元素的後代。
* `<link>` (en-US)，如果**itemprop** (en-US) 屬性存在。
* `<meta>` (en-US)，如果**itemprop** (en-US) 屬性存在。
* `<style>` (en-US)，如果 `scoped` (en-US) 屬性存在。
### 章節型內容（Sectioning content）

屬於章節型內容模型的元素會在該大綱裡面創立章節，這個章節會定義`<header>` (en-US)、`<footer>` (en-US)、還有heading content的範圍。

屬於這個類型的元素有`<article>` (en-US)、`<aside>` (en-US)、`<nav>`還有`<section>` (en-US)。

**備註：** 不要把這個內容模型，和把內容與常規大綱隔開的 sectioning root 類別搞混。

### 標題型內容（Heading content）

標題型內容定義了章節的標題，不論該章節由明確的章節型內容元素標記、抑或由標題本身隱式定義。

屬於這個類型的元素有`<h1>` (en-US)、`<h2>` (en-US)、`<h3>` (en-US), `<h4>` (en-US)、`<h5>` (en-US)、`<h6>` (en-US)還有`<hgroup>` (en-US).

**備註：** 儘管 `<header>` (en-US) 可能含有某些標題型內容，但它本身並不是。

### 段落型內容（Phrasing content）

段落型內容定義了文字、還有它包含的標記。Runs of phrasing content make up paragraphs.

屬於這個類型的元素有`<abbr>` (en-US)、`<audio>` (en-US)、`<b>` (en-US)、`<bdo>` (en-US)、`<br>`、`<button>` (en-US)、`<canvas>`、`<cite>` (en-US)、`<code>`、
已棄用
`<command>`、`<datalist>` (en-US)、`<dfn>` (en-US)、`<em>` (en-US)、`<embed>` (en-US)、`<i>` (en-US)、`<iframe>` (en-US)、`<img>` (en-US)、`<input>` (en-US)、`<kbd>` (en-US)、`<label>` (en-US)、`<mark>` (en-US)、`<math> (en-US)`、`<meter>` (en-US)、`<noscript>`、`<object>` (en-US)、`<output>` (en-US)、`<progress>` (en-US)、`<q>`、`<ruby>`、`<samp>` (en-US)、`<script>`、`<select>` (en-US)、`<small>` (en-US)、`<span>` (en-US)、`<strong>` (en-US)、`<sub>` (en-US)、`<sup>` (en-US)、`<svg>` (en-US)、`<textarea>` (en-US)、`<time>`、`<var>` (en-US)、`<video>` (en-US)、`<wbr>` (en-US)以及空白字符在內的純文本。

在滿足特定條件下，某些元素也屬這個類型：

* `<a>` (en-US)，如果它只包含段落型內容。
* `<area>` (en-US)，如果它是 `<map>` (en-US) 元素的後代。
* `<del>` (en-US)，如果它只包含段落型內容。
* `<ins>` (en-US), 如果它只包含段落型內容。
* `<link>` (en-US), 如果 **itemprop** (en-US) 屬性存在。
* `<map>` (en-US), 如果它只包含段落型內容。
* `<meta>` (en-US), 如果 **itemprop** (en-US) 屬性存在。
### 嵌入型內容（Embedded content）

嵌入型內容從其他標記語言或文件命名空間，導入資源或插入內容。 屬於這個類型的元素有`<audio>` (en-US)、`<canvas>`、`<embed>` (en-US)、`<iframe>` (en-US)、`<img>` (en-US)、`<math> (en-US)`、`<object>` (en-US)、`<svg>` (en-US)、`<video>` (en-US)。

### 互動型內容（Interactive content）

互動型內容包含專為用戶互動設計的元素。屬於這個類型的元素有 `<a>` (en-US)、`<button>` (en-US)、`<details>` (en-US)、`<embed>` (en-US)、`<iframe>` (en-US)、`<label>` (en-US)、`<select>` (en-US) 還有 `<textarea>` (en-US)。

在滿足特定條件下，某些元素也屬這個類型：

* `<audio>` (en-US)，如果 `controls` (en-US) 元素存在。
* `<img>` (en-US)，如果 `usemap` (en-US) 元素存在。
* `<input>` (en-US)，如果 `type` (en-US) 元素不是隱藏狀態。
* `<menu>` (en-US)，如果 `type` (en-US) 元素處於 toolbar 狀態。
* `<object>` (en-US)，如果 `usemap` (en-US) 元素存在。
* `<video>` (en-US)，如果 `controls` (en-US) 元素存在。
### 捫及內容（Palpable content）

不是空白或隱藏的內容稱為捫及。屬於流內容或是 Phrasing content 模型的元素最少要有一個捫及的節點。

### 表單相關內容（Form-associated content）

表單相關內容包含了由 **form** 屬性顯露的 form owner 元素。form owner 是本身包含於 `<form>` (en-US)、或 id 由 **form** 屬性指定的元素。

* `<button>` (en-US)
* `<fieldset>` (en-US)
* `<input>` (en-US)
* `<label>` (en-US)
* `<meter>` (en-US)
* `<object>` (en-US)
* `<output>` (en-US)
* `<progress>` (en-US)
* `<select>` (en-US)
* `<textarea>` (en-US)

本類型包含某些子類別:

listed

Elements that are listed in the form.elements (en-US) and fieldset.elements IDL collections. Contains `<button>` (en-US), `<fieldset>` (en-US), `<input>` (en-US), `<object>` (en-US), `<output>` (en-US), `<select>` (en-US), and `<textarea>` (en-US).

labelable

與元素 `<label>` (en-US) 相關的元素。包含 `<button>` (en-US)、`<input>` (en-US)、`<meter>` (en-US)、`<output>` (en-US)、`<progress>` (en-US)、`<select>` (en-US)、`<textarea>` (en-US)。

submittable

用在建構送出時，資料就設定好的表單元素。包含 `<button>` (en-US)、`<input>` (en-US)、`<object>` (en-US)、`<select>` (en-US)、`<textarea>` (en-US)。

resettable

當表單重設時會受影響的元素。包含 `<button>` (en-US)、`<input>` (en-US)、`<output>` (en-US)、`<select>` (en-US)、`<textarea>` (en-US)。

透明內容模型（Transparent content model）
---------------------------------

如果一個元素是透明內容模型，then its contents must be structured such that they would be valid HTML 5，就算該透明元素被移除、並由子元素取代。

例如，`<del>` (en-US) 與 `<ins>` (en-US) 元素都是透明的：
```

<p>我們認為下面這些真理是<del><em>神聖不可否認</em></del><ins>不言而喻的。</ins></p>
```

這果這些元素被刪掉的話，這個分段依然在 HTML 有效（if not correct English）
```

<p>我們認為下面這些真理是<em>神聖不可否認</em>不言而喻的。</p>
```

其他內容模型
------

章節根（Sectioning root）


<script> - HTML：超文本標記語言

<script>
========

**HTML `<script>` 元素**能嵌入或引用要執行的程式碼。最常見的用途是嵌入或引用 JavaScript 程式碼。`<script>` 元素也能執行其他語言，例如 WebGL (en-US) 的 GLSL shader 程式語言。

| 內容類型 | 元資料內容、流型內容、Phrasing content. |
| --- | --- |
| 允許的內容 | 動態腳本如 `text/javascript`. |
| 標籤省略 | None, both the starting and ending tag are mandatory. |
| 允許的父元素 | 任何可接受 元資料內容或 phrasing content 的元素。 |
| 允許的 ARIA role | None |
| DOM 介面 | `HTMLScriptElement` (en-US) |

屬性
--

此元素包含了全域屬性 (en-US)。

`async`

這個布林屬性告訴瀏覽器說：如果可以，就以非同步的方法執行腳本。

**警告：** 如果沒有 `src` 屬性的話，就不能用這個屬性（例如行內腳本）：在這種情況下，它將失去作用。

`async`

在 HTML 解析時，瀏覽器通常會假定最壞的情況，並同步地載入腳本（例如 `async=false`）。

動態插入的腳本（例如 `document.createElement`）一般來說是非同步執行的。因此，如果設定同步的話（腳本按照被插入的順序執行），會被設為 `async=false`。

請參見相容性註解的瀏覽器支援備註。另請參見 Async scripts for asm.js (en-US)。

`crossorigin`

針對沒有通過標準 CORS (en-US) 的一般 `script` 元素，會把最少的資訊傳給 `window.onerror` (en-US)。若要允許另一個域名站點的靜態內容，列出錯誤訊息，請使用此屬性。請參見 CORS settings attributes (en-US) 以以取得對其有效參數的，更具描述性的解釋。

`defer`

設置此 Boolean attribute 是為了指示瀏覽器，腳本應在 document 解析後，但在觸發 `DOMContentLoaded` (en-US) 之前被執行。具有 `defer` 屬性的腳本將阻止觸發 `DOMContentLoaded` 事件，直到腳本 load 完成並且 finished evaluating。

**警告：** 如果沒有 `src` 屬性的話，就不能用這個屬性（例如行內腳本）：在這種情況下，它將失去作用。The `defer` attribute has no effect on module script (en-US) — they defer by default.

`fetchpriority`

Scripts with the `defer` attribute will execute in the order in which they appear in the document.This attribute allows the elimination of **parser-blocking JavaScript** where the browser would have to load and evaluate scripts before continuing to parse. `async` has a similar effect in this case.

`integrity`

This attribute contains inline metadata that a user agent can use to verify that a fetched resource has been delivered free of unexpected manipulation. See Subresource Integrity (en-US).

`nomodule`

這個布林屬性，會要求支援 ES2015 modules 的瀏覽器，不執行裡面的程式。這能用來給不支援 JavaScript 模組的老舊瀏覽器，提供用於向下支援的服務。

`nonce`

A cryptographic nonce (number used once) to whitelist inline scripts in a script-src Content-Security-Policy (en-US). The server must generate a unique nonce value each time it transmits a policy. It is critical to provide a nonce that cannot be guessed as bypassing a resource's policy is otherwise trivial.

`src`

此屬性指定外部程式的 URI，可以用來取代直接在文件內中嵌入腳本。

**警告：** 如果 `script` 元素有指定 `src` 屬性的話，標籤內就不能有嵌入的腳本。

`text`

Like the `textContent` attribute, this attribute sets the text content of the element. Unlike the `textContent` attribute, however, this attribute is evaluated as executable code after the node is inserted into the DOM.

`type`

此屬性指定程式碼應該表示的類型。此屬性的值會屬於以下類別之一：**省略或 JavaScript MIME 類型**：針對相容 HTML5 的瀏覽器來說，元素內會執行 JavaScript。HTML5 規範敦促作者省略此屬性，不需要寫冗長的 MIME 類型。在早期的瀏覽器中，這確定了嵌入或引入（透過 `src` 屬性）腳本的語言。JavaScript MIME 類型有列在規範內 (en-US)。

* **`module`**：針對相容 HTML5 的瀏覽器來說，這段程式碼會當成 JavaScript 模組（module）。腳本內容的處理不受 `charset` 與 `defer` 屬性影響。針對 `module` 的資訊，請參閱 ES6 in Depth: Modules。在使用 `module` 關鍵字時，程式碼的行為會有所不同。
* **其他值**：嵌入的內容會被當成一段不給瀏覽器執行的資料塊（data block）。開發者應當使用非 JavaScript 的有效 MIME 類型，以標明資料塊。`src` 屬性也將被忽略。

**備註：** 在 Firefox 你可以在 `<script>` 元素的 `type` 屬性，透過標明非標準參數 `version`，指定要使用的 JavaScript 版本：例如說 `type="application/javascript;version=1.8"`。這個功能在 Firefox 59 移除了（請參見 Firefox bug 1428745）。

### 棄用屬性

`language`
已棄用

如同 `type` 屬性，此屬性指定正在使用的腳本語言。但與 `type` 屬性不同，此屬性的可用值從未標準化。應當使用 `type` 屬性。

註解
--

Scripts without `async` or `defer` attributes, as well as inline scripts, are fetched and executed immediately, before the browser continues to parse the page.

The script should be served with the `text/javascript` MIME type, but browsers are lenient and only block them if the script is served with an image type (`image/*`); a video type (`video/*`); an audio (`audio/*`) type; or `text/csv`. If the script is blocked, an `error` (en-US) is sent to the element, if not a `load` (en-US) event is sent.

示例
--

### 基本

以下示例展示如何在 HTML4 與 HTML5 使用 `<script>` 屬性。

```html
<!-- HTML4 與 (x)HTML -->
<script type="text/javascript" src="javascript.js"></script>

<!-- HTML5 -->
<script src="javascript.js"></script>
```

### 模組的向下支援方案

有針對 type 屬性支援 module（模組）的瀏覽器，會忽略 nomodule 屬性的程式碼。這能讓那些不支援模組的瀏覽器，提供替代的使用方法。

```js
<script type="module" src="main.mjs"></script>
<script nomodule src="fallback.js"></script>
```

規範
--

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

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

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

相容性註解
-----

In older browsers that don't support the `async` attribute, parser-inserted scripts block the parser; script-inserted scripts execute asynchronously in IE and WebKit, but synchronously in Opera and pre-4 Firefox. In Firefox 4, the `async` DOM property defaults to `true` for script-created scripts, so the default behaviour matches the behaviour of IE and WebKit.

To request script-inserted external scripts be executed in the insertion order in browsers where the `document.createElement("script").async` evaluates to `true` (such as Firefox 4), set `.async=false` on the scripts you want to maintain order.

**警告：** Never call `document.write()` from an async script. In Firefox 3.6, calling `document.write()` has an unpredictable effect. In Firefox 4, calling `document.write()` from an async script has no effect (other than printing a warning to the error console).

參見
--

* `document.currentScript` (en-US)
* Ryan Grove's <script> and <link> node event compatibility chart


<ruby> - HTML：超文本標記語言

<ruby>
======

**HTML `<ruby>` 元素**的意思是旁註標記。旁註標記用於標示東亞文字的發音。

嘗試一下
----

| 內容類型 | 流內容、段落型內容、捫及內容 |
| --- | --- |
| 允許內容 | 段落型內容 |
| 標籤省略 | None, both the starting and ending tag are mandatory. |
| 允許父元素 | Any element that accepts phrasing content (en-US) |
| DOM 介面 | `HTMLElement` (en-US) |

屬性
--

這個元素只支援全域屬性 (en-US)。

範例
--

### 範例一：字

```html
<ruby>
  漢 <rp>(</rp><rt>Kan</rt><rp>)</rp> 字 <rp>(</rp><rt>ji</rt><rp>)</rp>
</ruby>
```

### 範例二：詞

```html
<ruby> 明日 <rp>(</rp><rt>Ashita</rt><rp>)</rp> </ruby>
```

規範
--

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

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

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

參閱
--

* `<rt>` (en-US)
* `<rp>` (en-US)
* `<rb>` (en-US)
* `<rtc>` (en-US)
* `<rbc>`
* `text-transform` (en-US): full-size-kana


<head> - HTML：超文本標記語言

<head>
======

HTML 中的 **`<head>`** 元素包含有關文件的機器可讀信息（後設資料），例如 標題、腳本、樣式表 (en-US)。

**備註：**`<head>` 主要保存用於機器處理的訊息，而不是人類可讀的訊息。對於人類可見的訊息，例如頂級標題和列出的作者，請參見 `<header>` (en-US) 元素。

屬性
--

這個元件屬性含有全域屬性 (en-US)。

範例
--

```html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Document title</title>
  </head>
</html>
```

技術摘要
----

|  |  |
| --- | --- |
| 內容類型 | 無 |
| 允許內容 |
 如果文件是一個 `<iframe>` (en-US)
`srcdoc` (en-US) 文件，或者如果標題信息來自於更高級的協議（像是 HTML 電子郵件的主題行），則應包含零個或多個元素的後設資料內容。

否則，必須包含一個或多個元素的後設資料內容，其中確實包括一個 `<title>` 元素。 |
| 標籤省略 |
 如果
 `<head>` 元素內的第一個內容是一個元素，則開起標籤可以省略。如果跟在
 `<head>` 元素後面的第一個內容不是空格字符或註釋，則關閉標籤可以省略。
  |
| 允許的父元素 | 作為 `<html>` (en-US) 元素的第一個子元素。 |
| 允許的 ARIA 角色 | 沒有允許的 `role` |
| DOM 介面 | `HTMLHeadElement` (en-US) |

規範
--

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

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

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

參見
--

* 可以使用在 `<head>` 中的元素：
    + `<title>`
    + `<base>` (en-US)
    + `<link>` (en-US)
    + `<style>` (en-US)
    + `<meta>` (en-US)
    + `<script>`
    + `<noscript>`
    + `<template>`


<marquee>：捲動元素（已過時） - HTML：超文本標記語言

<marquee>：捲動元素（已過時）
===================

**已棄用:** 不推薦使用此功能。雖可能有一些瀏覽器仍然支援它，但也許已自相關的網頁標準中移除、正準備移除、或僅為了維持相容性而保留。避免使用此功能，盡可能更新現有程式；請參考頁面底部的相容性表格來下決定。請注意：本功能可能隨時停止運作。

HTML `<marquee>` 元素用作插入一段文字的捲動區域。你可以透過屬性，控制文字在到達邊緣後的應對動作。

|  |  |
| --- | --- |
| DOM 介面 | `HTMLMarqueeElement` (en-US) |

屬性
--

`behavior`

設定文字如何在 marquee 內捲動。可用值為 `scroll`、`slide`、`alternate`。若無指定，預設值為 `scroll`。

`bgcolor`

透過色彩名或十六進位值指定背景顏色。

`direction`

設定 marquee 內的捲動方向。可用值為 `left`、`right`、`up`、`down`。若無指定，預設值為 `left`。

`height`

設定像素或百分比高度。

`hspace`

設定橫向外邊（horizontal margin）

`loop`

設定 marquee 捲動的次數。若無指定，預設值為 -1，意思是的 marquee 將持續捲動。

`scrollamount`

以像素為單位，設定捲動的間隔量。預設值為 6。

`scrolldelay`

設定每次捲動時之間間隔的毫秒。預設值為 85。請注意，除非指定了 `truespeed`，否則小於 60 的數字會被忽略，並值使用 60。

`truespeed`

`scrolldelay` 預設上會忽略低於 60 的值。但如果有 `truespeed` 的話，就不會忽略此值。

`vspace`

以像素或百分比值設置垂直邊距。

`width`

設置以像素或百分比值為單位的寬度。

事件處理器
-----

`onbounce`

marquee 滾動到結尾時觸發。只能在 behavior 屬性設置為 `alternate` 時觸發。

`onfinish`

marquee 完成 loop 屬性的設定值時觸發。只能在 loop 屬性設為大於 0 的數字時觸發。

`onstart`

marquee 開始捲動時觸發。

方法
--

start()

開始 marquee 的捲動

stop()

停止 marquee 的捲動

示例
--

```html
<marquee>This text will scroll from right to left</marquee>

<marquee direction="up">This text will scroll from bottom to top</marquee>

<marquee
 direction="down"
 width="250"
 height="200"
 behavior="alternate"
 style="border:solid">
  <marquee behavior="alternate">This text will bounce</marquee>
</marquee>
```

規範
--

| Specification |
| --- |
| HTML Standard # the-marquee-element-2 |

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

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

參見
--

* `HTMLMarqueeElement` (en-US)