内容

dart:html

使用 dart:html 库来编写浏览器,操作 DOM 中的对象和元素,以及访问 HTML5 API。DOM 代表文档对象模型,它描述了 HTML 页面的层次结构。

dart:html 的其他常见用途包括操作样式 (CSS)、使用 HTTP 请求获取数据以及使用 WebSockets 交换数据。HTML5 (和 dart:html) 具有许多本节未涵盖的额外 API。只有 Web 应用程序可以使用 dart:html,命令行应用程序不能使用。

要在 Web 应用程序中使用 HTML 库,请导入 dart:html

dart
import 'dart:html';

操作 DOM

#

要使用 DOM,您需要了解窗口文档元素节点

Window 对象代表 Web 浏览器的实际窗口。每个 Window 都有一个 Document 对象,它指向当前加载的文档。Window 对象还可以访问各种 API,例如 IndexedDB(用于存储数据)、requestAnimationFrame(用于动画)等等。在选项卡式浏览器中,每个选项卡都有自己的 Window 对象。

使用 Document 对象,您可以创建和操作文档内的 Element 对象。请注意,文档本身就是一个元素,可以进行操作。

DOM 对 Node 树进行建模。这些节点通常是元素,但也可以是属性、文本、注释和其他 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 定义所有元素具有的属性。例如,所有元素都有 classeshiddenidstyletitle 属性,您可以使用这些属性来设置状态。Element 的子类定义了其他属性,例如 AnchorElementhref 属性。

考虑以下在 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 = 'https://dart.ac.cn';

通常您需要对多个元素设置属性。例如,以下代码将所有具有“mac”、“win”或“linux”类的元素的 hidden 属性设置为 true。将 hidden 属性设置为 true 的效果与在 CSS 中添加 display: none 相同。

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>(与 children 相反,children 省略了非 Element 节点)。获得此列表后,您可以使用常用的 List 方法和运算符来操作节点的子节点。

要将节点作为其父节点的最后一个子节点添加,请使用 List 的 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 请求。dart:html 中的 HttpRequest 类是平台相关的,并且绑定到单个实现。相反,请使用更高层的库,例如 package:http

从互联网获取数据 教程解释了如何使用 package:http 进行 HTTP 请求。

使用 WebSockets 发送和接收实时数据

#

WebSocket 允许您的 Web 应用程序与服务器交互式地交换数据——无需轮询。服务器创建 WebSocket 并监听以以 ws:// 开头的 URL 上的请求——例如,ws://127.0.0.1:1337/ws。通过 WebSocket 传输的数据可以是字符串或 Blob。通常,数据是 JSON 格式的字符串。

要在您的 Web 应用程序中使用 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 事件:open、close、error 和(如前所示)message。以下是一个创建 WebSocket 对象并为 open、close、error 和 message 事件注册处理程序的方法示例

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 有用于更专业的 Web API 的其他库,例如 web 音频IndexedDBWebGL

有关 Dart Web 库的更多信息,请参阅 Web 库概述