內容

使用 dart:html 函式庫來編寫瀏覽器程式、處理 DOM 中的物件和元素,以及存取 HTML5 API。DOM 代表文件物件模型,用來描述 HTML 頁面的階層結構。

dart:html 的其他常見用途包括處理樣式 (CSS)、使用 HTTP 要求取得資料,以及使用 WebSocket 交換資料。HTML5 (和 dart:html) 有許多額外的 API,本節未涵蓋。只有網頁應用程式可以使用 dart:html,命令列應用程式不行。

要在您的網頁應用程式中使用 HTML 函式庫,請匯入 dart:html

dart
import 'dart:html';

操作 DOM

#

要使用 DOM,您需要了解視窗文件元素節點

視窗 物件代表網頁瀏覽器的實際視窗。每個視窗都有文件物件,指向目前載入的文件。視窗物件也可以存取各種 API,例如 IndexedDB (用於儲存資料)、requestAnimationFrame (用於動畫) 等。在分頁瀏覽器中,每個分頁都有自己的視窗物件。

使用 文件 物件,您可以在文件中建立和處理 元素 物件。請注意,文件本身是一個元素,可以進行處理。

DOM 模擬 節點 樹狀結構。這些節點通常是元素,但它們也可以是屬性、文字、註解和其他 DOM 類型。除了沒有父項目的根節點外,DOM 中的每個節點都有單一父項目,並且可能有多個子項目。

尋找元素

#

要操作元素,首先需要一個代表它的物件。你可以使用查詢來取得這個物件。

使用頂層函式 `querySelector()` 和 `querySelectorAll()` 尋找一個或多個元素。你可以透過 ID、類別、標籤、名稱或這些的任意組合來查詢。CSS 選擇器規格指南 定義了選擇器的格式,例如使用 # 前綴來指定 ID,而使用句點 (.) 來指定類別。

函式 `querySelector()` 會傳回與選擇器相符的第一個元素,而 `querySelectorAll()` 會傳回與選擇器相符的元素集合。

dart
// Find an element by id (an-id).
Element idElement = querySelector('#an-id')!;

// Find an element by class (a-class).
Element classElement = querySelector('.a-class')!;

// Find all elements by tag (<div>).
List<Element> divElements = querySelectorAll('div');

// Find all text inputs.
List<Element> textInputElements = querySelectorAll(
  'input[type="text"]',
);

// Find all elements with the CSS class 'class'
// inside of a <p> that is inside an element with
// the ID 'id'.
List<Element> specialParagraphElements = querySelectorAll('#id p.class');

操作元素

#

你可以使用屬性來變更元素的狀態。Node 及其子類型 Element 定義了所有元素都具有的屬性。例如,所有元素都有 `classes`、`hidden`、`id`、`style` 和 `title` 屬性,你可以使用這些屬性來設定狀態。Element 的子類別會定義其他屬性,例如 AnchorElement 的 `href` 屬性。

考慮這個在 HTML 中指定錨點元素的範例

html
<a id="example" href="/another/example">link text</a>

這個 <a> 標籤指定了一個具有 `href` 屬性以及包含字串「連結文字」的文字節點(可透過 `text` 屬性存取)的元素。若要變更連結指向的 URL,你可以使用 AnchorElement 的 `href` 屬性

dart
var anchor = querySelector('#example') as AnchorElement;
anchor.href = 'http://dart.dev.org.tw';

你常常需要設定多個元素的屬性。例如,以下程式碼會設定所有具有類別「mac」、「win」或「linux」的元素的 `hidden` 屬性。將 `hidden` 屬性設定為 true 的效果與將 `display: none` 加入 CSS 相同。

html
<!-- In HTML: -->
<p>
  <span class="linux">Words for Linux</span>
  <span class="macos">Words for Mac</span>
  <span class="windows">Words for Windows</span>
</p>
dart
// In Dart:
const osList = ['macos', 'windows', 'linux'];
final userOs = determineUserOs();

// For each possible OS...
for (final os in osList) {
  // Matches user OS?
  bool shouldShow = (os == userOs);

  // Find all elements with class=os. For example, if
  // os == 'windows', call querySelectorAll('.windows')
  // to find all elements with the class "windows".
  // Note that '.$os' uses string interpolation.
  for (final elem in querySelectorAll('.$os')) {
    elem.hidden = !shouldShow; // Show or hide.
  }
}

當適當的屬性不可用或不方便時,你可以使用 Element 的 `attributes` 屬性。這個屬性是一個 `Map<String, String>`,其中金鑰是屬性名稱。有關屬性名稱及其意義的清單,請參閱 MDN 屬性頁面。以下是設定屬性值的範例

dart
elem.attributes['someAttribute'] = 'someValue';

建立元素

#

你可以透過建立新元素並將它們附加到 DOM 來新增到現有的 HTML 頁面。以下是建立段落 (<p>) 元素的範例

dart
var elem = ParagraphElement();
elem.text = 'Creating is easy!';

你也可以透過剖析 HTML 文字來建立元素。任何子元素也會被剖析並建立。

dart
var elem2 = Element.html(
  '<p>Creating <em>is</em> easy!</p>',
);

請注意,在前面的範例中 `elem2` 是 `ParagraphElement`。

透過將父元素指定給元素,將新建立的元素附加到文件。你可以將元素新增到任何現有元素的子元素。在以下範例中,`body` 是元素,而它的子元素可從 `children` 屬性存取(作為 `List<Element>`)。

dart
document.body!.children.add(elem2);

新增、取代和移除節點

#

請回想,元素只不過是一種節點。你可以使用 Node 的 `nodes` 屬性來尋找節點的所有子元素,該屬性會傳回 `List<Node>`(與省略非 Element 節點的 `children` 相反)。取得這個清單後,你可以使用一般的清單方法和運算子來操作節點的子元素。

若要將節點新增為其父元素的最後一個子元素,請使用清單 `add()` 方法

dart
querySelector('#inputs')!.nodes.add(elem);

若要取代節點,請使用 Node `replaceWith()` 方法

dart
querySelector('#status')!.replaceWith(elem);

若要移除節點,請使用 Node remove() 方法

dart
// Find a node by ID, and remove it from the DOM if it is found.
querySelector('#expendable')?.remove();

操作 CSS 樣式

#

CSS 或 層疊樣式表定義 DOM 元素的呈現樣式。您可以透過附加 ID 和類別屬性來變更元素的外觀。

每個元素都有 classes 欄位,它是一個清單。只要從這個集合中新增和移除字串,就可以新增和移除 CSS 類別。例如,下列範例會將 warning 類別新增到元素中

dart
var elem = querySelector('#message')!;
elem.classes.add('warning');

通常透過 ID 尋找元素非常有效率。您可以使用 id 屬性動態設定元素 ID

dart
var message = DivElement();
message.id = 'message2';
message.text = 'Please subscribe to the Dart mailing list.';

您可以使用方法串接來減少此範例中的重複文字

dart
var message = DivElement()
  ..id = 'message2'
  ..text = 'Please subscribe to the Dart mailing list.';

雖然使用 ID 和類別將元素與一組樣式關聯是最佳做法,但有時您會想要直接將特定樣式附加到元素中

dart
message.style
  ..fontWeight = 'bold'
  ..fontSize = '3em';

處理事件

#

若要回應外部事件,例如點擊、焦點變更和選取,請新增事件聆聽器。您可以將事件聆聽器新增到頁面上的任何元素。事件分派和傳遞是一個複雜的主題;研究詳細資訊,如果您不熟悉網頁程式設計。

使用 element.onEvent.listen(function) 新增事件處理常式,其中 Event 是事件名稱,而 function 是事件處理常式。

例如,以下是處理按鈕點擊的方法

dart
// Find a button by ID and add an event handler.
querySelector('#submitInfo')!.onClick.listen((e) {
  // When the button is clicked, it runs this code.
  submitData();
});

事件可以透過 DOM 樹向上和向下傳遞。若要找出最初觸發事件的元素,請使用 e.target

dart
document.body!.onClick.listen((e) {
  final clickedElem = e.target;
  // ...
});

若要查看您可以為其註冊事件聆聽器的所有事件,請在 Element 及其子類別的 API 文件中尋找「onEventType」屬性。一些常見的事件包括

  • change
  • blur
  • keyDown
  • keyUp
  • mouseDown
  • mouseUp

使用 HttpRequest 處理 HTTP 資源

#

您應該避免直接使用 dart:html 來發出 HTTP 要求。HttpRequest 類別在 dart:html 中是依賴於平台的,而且與單一實作綁定。請改用較高層級的函式庫,例如 package:http

教學課程 從網際網路擷取資料 說明如何使用 package:http 發出 HTTP 要求。

使用 WebSocket 傳送和接收即時資料

#

WebSocket 讓您的網頁應用程式可以與伺服器互動式地交換資料,無需輪詢。伺服器會建立 WebSocket,並在以 ws:// 開頭的 URL 上聆聽要求,例如 ws://127.0.0.1:1337/ws。透過 WebSocket 傳輸的資料可以是字串或二進位大型物件。通常,資料是 JSON 格式的字串。

若要在您的網頁應用程式中使用 WebSocket,請先建立 WebSocket 物件,傳遞 WebSocket URL 作為引數

dart
var ws = WebSocket('ws://echo.websocket.org');

傳送資料

#

若要在 WebSocket 上傳送字串資料,請使用 send() 方法

dart
ws.send('Hello from Dart!');

接收資料

#

若要接收 WebSocket 上的資料,請為訊息事件註冊一個監聽器

dart
ws.onMessage.listen((MessageEvent e) {
  print('Received message: ${e.data}');
});

訊息事件處理常式會接收一個 MessageEvent 物件。此物件的 data 欄位包含來自伺服器的資料。

處理 WebSocket 事件

#

您的應用程式可以處理下列 WebSocket 事件:開啟、關閉、錯誤,以及(如前所述)訊息。以下是建立 WebSocket 物件並為開啟、關閉、錯誤和訊息事件註冊處理常式的範例方法

dart
void initWebSocket([int retrySeconds = 1]) {
  var reconnectScheduled = false;

  print('Connecting to websocket');

  void scheduleReconnect() {
    if (!reconnectScheduled) {
      Timer(Duration(seconds: retrySeconds),
          () => initWebSocket(retrySeconds * 2));
    }
    reconnectScheduled = true;
  }

  ws.onOpen.listen((e) {
    print('Connected');
    ws.send('Hello from Dart!');
  });

  ws.onClose.listen((e) {
    print('Websocket closed, retrying in $retrySeconds seconds');
    scheduleReconnect();
  });

  ws.onError.listen((e) {
    print('Error connecting to ws');
    scheduleReconnect();
  });

  ws.onMessage.listen((MessageEvent e) {
    print('Received message: ${e.data}');
  });
}

更多資訊

#

此節僅簡略介紹 dart:html 函式庫的使用方式。如需詳細資訊,請參閱 dart:html 的文件。Dart 有其他函式庫可支援更專業的網路 API,例如 網路音訊IndexedDBWebGL

如需有關 Dart 網路函式庫的詳細資訊,請參閱 網路函式庫概觀