dart:html
使用 dart:html 庫來程式設計瀏覽器,操作 DOM 中的物件和元素,並訪問 HTML5 API。DOM 指的是 Document Object Model,它描述了 HTML 頁面的層級結構。
dart:html 的其他常見用途包括操作樣式 (CSS),使用 HTTP 請求獲取資料,以及使用 WebSocket 交換資料。HTML5(以及 dart:html)還有許多本節未涵蓋的其他 API。只有 Web 應用可以使用 dart:html,命令列應用則不能。
要在您的 Web 應用中使用 HTML 庫,請匯入 dart:html
import 'dart:html';操作 DOM
#要使用 DOM,您需要了解視窗、文件、元素和節點。
Window 物件代表 Web 瀏覽器的實際視窗。每個 Window 都有一個 Document 物件,指向當前載入的文件。Window 物件還提供了訪問各種 API 的訪問器,例如 IndexedDB(用於儲存資料)、requestAnimationFrame(用於動畫)等。在標籤頁瀏覽器中,每個標籤頁都有自己的 Window 物件。
使用 Document 物件,您可以在文件中建立和操作 Element 物件。請注意,文件本身也是一個元素,可以進行操作。
DOM 將 節點 建模為樹形結構。這些節點通常是元素,但也可以是屬性、文字、註釋和其他 DOM 型別。除了沒有父節點的根節點外,DOM 中的每個節點都有一個父節點,並且可能有很多子節點。
查詢元素
#要操作一個元素,您首先需要一個代表它的物件。您可以使用查詢來獲取此物件。
使用頂級函式 querySelector() 和 querySelectorAll() 查詢一個或多個元素。您可以按 ID、類、標籤、名稱或這些的任意組合進行查詢。CSS 選擇器規範指南 定義了選擇器的格式,例如使用 # 字首指定 ID,使用點號 (.) 指定類。
querySelector() 函式返回第一個匹配選擇器的元素,而 querySelectorAll() 返回一個匹配選擇器的元素集合。
// 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 中指定錨點元素的示例
<a id="example" href="/another/example">link text</a>此 <a> 標籤指定了一個具有 href 屬性和文字節點(可透過 text 屬性訪問)的元素,該文字節點包含字串 "link text"。要更改連結指向的 URL,您可以使用 AnchorElement 的 href 屬性
var anchor = querySelector('#example') as AnchorElement;
anchor.href = 'https://dart.lang.tw';通常您需要在多個元素上設定屬性。例如,以下程式碼設定了所有具有類名 "mac"、"win" 或 "linux" 的元素的 hidden 屬性。將 hidden 屬性設定為 true 的效果與在 CSS 中新增 display: none 相同。
<!-- 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>// 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 Attributes 頁面。以下是設定屬性值的示例
elem.attributes['someAttribute'] = 'someValue';建立元素
#您可以透過建立新元素並將其附加到 DOM 來新增到現有 HTML 頁面。以下是建立一個段落 (<p>) 元素的示例
var elem = ParagraphElement();
elem.text = 'Creating is easy!';您還可以透過解析 HTML 文字來建立元素。任何子元素也會被解析和建立。
var elem2 = Element.html('<p>Creating <em>is</em> easy!</p>');請注意,在前面的示例中,elem2 是一個 ParagraphElement。
透過為元素分配父節點,將新建立的元素附加到文件。您可以將元素新增到任何現有元素的子節點中。在下面的示例中,body 是一個元素,其子元素可從 children 屬性訪問(作為 List<Element>)。
document.body!.children.add(elem2);新增、替換和移除節點
#回想一下,元素只是一種節點。您可以使用 Node 的 nodes 屬性查詢節點的所有子節點,該屬性返回一個 List<Node>(與 children 不同,children 會忽略非 Element 節點)。獲得此列表後,您可以使用常用的 List 方法和運算子來操作節點的子節點。
要將節點新增為其父節點的最後一個子節點,請使用 List 的 add() 方法
querySelector('#inputs')!.nodes.add(elem);要替換節點,請使用 Node 的 replaceWith() 方法
querySelector('#status')!.replaceWith(elem);要移除節點,請使用 Node 的 remove() 方法
// Find a node by ID, and remove it from the DOM if it is found.
querySelector('#expendable')?.remove();操作 CSS 樣式
#CSS,即 Cascading Style Sheets,定義了 DOM 元素的呈現樣式。您可以透過為其附加 ID 和 class 屬性來改變元素的顯示外觀。
每個元素都有一個 classes 欄位,它是一個列表。只需透過在此集合中新增和移除字串來新增和移除 CSS 類。例如,以下示例將 warning 類新增到元素
var elem = querySelector('#message')!;
elem.classes.add('warning');按 ID 查詢元素通常非常高效。您可以使用 id 屬性動態設定元素 ID
var message = DivElement();
message.id = 'message2';
message.text = 'Please subscribe to the Dart mailing list.';您可以使用方法級聯來減少此示例中的冗餘文字
var message = DivElement()
..id = 'message2'
..text = 'Please subscribe to the Dart mailing list.';雖然使用 ID 和類將元素與一組樣式關聯起來是最佳實踐,但有時您可能希望直接將特定樣式附加到元素上
message.style
..fontWeight = 'bold'
..fontSize = '3em';處理事件
#要響應外部事件,例如點選、焦點改變和選擇,請新增事件監聽器。您可以將事件監聽器新增到頁面上的任何元素。事件分派和傳播是一個複雜的主題;如果您剛接觸 Web 程式設計,請深入研究其細節。
使用 element.onEvent.listen(function) 新增事件處理器,其中 Event 是事件名稱,function 是事件處理器。
例如,以下是如何處理按鈕點選
// 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
document.body!.onClick.listen((e) {
final clickedElem = e.target;
// ...
});要檢視所有可以註冊事件監聽器的事件,請查閱 Element 及其子類的 API 文件中帶有 "onEventType" 格式的屬性。一些常見的事件包括
- change
- blur
- keyDown
- keyUp
- mouseDown
- mouseUp
使用 HttpRequest 處理 HTTP 資源
#您應該避免直接使用 dart:html 來發出 HTTP 請求。dart:html 中的 HttpRequest 類依賴於平臺,並且僅繫結到單一實現。請轉而使用更高級別的庫,例如 package:http。
“從網際網路獲取資料”教程解釋瞭如何使用 package:http 發出 HTTP 請求。
使用 WebSocket 傳送和接收即時資料
#WebSocket 允許您的 Web 應用與伺服器互動式地交換資料——無需輪詢。伺服器建立 WebSocket 並在以 ws:// 開頭的 URL 上監聽請求——例如,ws://127.0.0.1:1337/ws。透過 WebSocket 傳輸的資料可以是字串或 blob。通常,資料是 JSON 格式的字串。
要在您的 Web 應用中使用 WebSocket,首先建立一個 WebSocket 物件,並將 WebSocket URL 作為引數傳遞
var ws = WebSocket('ws://echo.websocket.org');傳送資料
#要在 WebSocket 上傳送字串資料,請使用 send() 方法
ws.send('Hello from Dart!');接收資料
#要在 WebSocket 上接收資料,請為 message 事件註冊監聽器
ws.onMessage.listen((MessageEvent e) {
print('Received message: ${e.data}');
});message 事件處理器接收一個 MessageEvent 物件。此物件的 data 欄位包含來自伺服器的資料。
處理 WebSocket 事件
#您的應用可以處理以下 WebSocket 事件:open、close、error 和(如前所示)message。以下是建立 WebSocket 物件併為 open、close、error 和 message 事件註冊處理器的示例方法
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 還提供用於更專業 Web API 的其他庫,例如 web audio、IndexedDB 和 WebGL。
有關 Dart Web 庫的更多資訊,請參閱Web 庫概覽。