コンテンツ

dart:html

dart:html ライブラリを使用して、ブラウザをプログラムし、DOM内のオブジェクトと要素を操作し、HTML5 APIにアクセスします。DOMは、HTMLページの階層を記述する *Document Object Model* の略です。

dart:htmlのその他の一般的な用途は、スタイル(*CSS*)の操作、HTTPリクエストを使用したデータの取得、WebSocketを使用したデータの交換です。HTML5(およびdart:html)には、このセクションで説明しない追加のAPIが多数あります。dart:htmlを使用できるのは、コマンドラインアプリではなく、Webアプリのみです。

WebアプリでHTMLライブラリを使用するには、dart:htmlをインポートします

dart
import 'dart:html';

DOMの操作

#

DOMを使用するには、*ウィンドウ*、*ドキュメント*、*要素*、および*ノード*について知っておく必要があります。

Window オブジェクトは、Webブラウザーの実際のウィンドウを表します。各WindowにはDocumentオブジェクトがあり、現在ロードされているドキュメントを指します。Windowオブジェクトには、IndexedDB(データの保存用)、requestAnimationFrame(アニメーション用)など、さまざまなAPIへのアクセサーもあります。タブ付きブラウザーでは、各タブに独自のWindowオブジェクトがあります。

Documentオブジェクトを使用すると、ドキュメント内でElementオブジェクトを作成および操作できます。ドキュメント自体が要素であり、操作できることに注意してください。

DOMは、Nodeのツリーをモデル化します。これらのノードは多くの場合要素ですが、属性、テキスト、コメント、およびその他のDOM型である場合もあります。親を持たないルートノードを除き、DOM内の各ノードには1つの親があり、多くの子を持つ場合があります。

要素の検索

#

要素を操作するには、まずそれを表すオブジェクトが必要です。このオブジェクトは、クエリを使用して取得できます。

トップレベル関数querySelector()querySelectorAll()を使用して、1つ以上の要素を検索します。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は、すべての要素が持つプロパティを定義します。たとえば、すべての要素には、状態を設定するために使用できるclasseshiddenidstyle、およびtitleプロパティがあります。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.dokyumento.jp';

多くの場合、複数の要素にプロパティを設定する必要があります。たとえば、次のコードは、「mac」、「win」、または「linux」のクラスを持つすべての要素のhiddenプロパティを設定します。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>',
);

上記の例では、elem2ParagraphElementであることに注意してください。

新しく作成した要素を、要素に親を割り当てることでドキュメントにアタッチします。任意の既存の要素の子に要素を追加できます。次の例では、bodyは要素であり、その子要素は、childrenプロパティから(List<Element>として)アクセスできます。

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

ノードの追加、置換、削除

#

要素は単なるノードの一種であることを思い出してください。ノードのすべての子は、Nodeのnodesプロパティを使用して検索できます。これにより、List<Node>が返されます(Element以外のノードを省略するchildrenとは対照的です)。このリストがあれば、通常の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';

イベントの処理

#

クリック、フォーカスの変更、選択などの外部イベントに応答するには、イベントリスナーを追加します。ページの任意の要素にイベントリスナーを追加できます。イベントのディスパッチと伝播は複雑な主題です。Webプログラミングが初めての場合は、詳細を調べてください

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リソースの使用

#

HTTPリクエストを行うためにdart:htmlを直接使用することは避けるべきです。dart:htmlHttpRequestクラスはプラットフォームに依存し、単一の実装に縛られています。代わりに、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を渡します。

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イベントの処理

#

アプリは、open、close、error、および(前述のように)messageのWebSocketイベントを処理できます。以下は、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オーディオIndexedDB、およびWebGLなど、より特殊なWeb API用の追加ライブラリがあります。

Dart Webライブラリの詳細については、Webライブラリの概要を参照してください。