イベントハンドリング – Dart逆引きリファレンス

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

イベントハンドリング(Event handling)

W3CのDOMで仕様化されている「addEventListener」や「removeEventListener」は用いません。そのかわり、Dart Editorのコード補完で滑らかに入力することができる記法となっています。

ExampleEventHandling.html

<!DOCTYPE html>

<html>
  <head>
    <title>ExampleEventHandling</title>
  </head>
  <body>
    <h1>ExampleEventHandling</h1>
    <h2 id="toc-dart-is-not-running" id="status">dart is not running</h2>
    <script type="application/dart" src="ExampleEventHandling.dart"></script>
    <script src="http://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>
  </body>
</html>

ターゲットにイベントハンドラを追加したい

イベントハンドラを追加する記述の流れは下記の通りです。

  1. イベントターゲットの持つ「on」プロパティを参照。
    • ターゲットが持つイベント群が得られる。
  2. イベント群「on」からイベントタイプを表す任意のプロパティ(click等)を参照。
    • イベントリスナのリストオブジェクトが得られる。
  3. イベントリスナのリストオブジェクトが持つ「add」メソッドを使用してイベントハンドラを追加。

ExampleEventHandling.dart

#import('dart:html');

class Example {
  Element element;
  Example(): element = document.query('#target');
  void run() {
    element.on.mouseOver.add(mouseOverHandler);
    element.on.mouseOut.add(mouseOutHandler);
  }
  mouseOverHandler(MouseEvent event) => element.innerHTML = 'dart';
  mouseOutHandler(MouseEvent event) => element.innerHTML = 'world';
}

void main() {
  document.query('#status').innerHTML = 'Hello, <span id="target">world</span>!';
  new Example().run();
}

ターゲットからイベントハンドラを除去したい

イベントハンドラを除去する記述の流れは下記の通りです。

  1. イベントターゲットの持つ「on」プロパティを参照。
    • ターゲットが持つイベント群が得られる。
  2. イベント群「on」からイベントタイプを表す任意のプロパティ(click等)を参照。
    • イベントリスナのリストオブジェクトが得られる。
  3. イベントリスナのリストオブジェクトが持つ「remove」メソッドを使用してイベントハンドラを除去。

ExampleEventHandling.dart

#import('dart:html');

class Example {
  Element element;
  Example(): element = document.query('#target');
  void run() {
    element.on.mouseOver.add(mouseOverHandler);
    element.on.mouseOut.add(mouseOutHandler);
    document.on.click.add(clickHandler);
  }
  mouseOverHandler(MouseEvent event) => element.innerHTML = 'dart';
  mouseOutHandler(MouseEvent event) => element.innerHTML = 'world';
  clickHandler(MouseEvent event) {
    element.on.mouseOver.remove(mouseOverHandler);
    element.on.mouseOut.remove(mouseOutHandler);
  }
}

void main() {
  document.query('#status').innerHTML = 'Hello, <span id="target">world</span>!';
  new Example().run();
}

ただし2012年5月23日現在、removeメソッドでイベントハンドラが除去されない問題があるようです。

Issue 144: How to compare if two functions are equal.

この問題は、イベントハンドラをインスタンス変数へ代入しておき、イベントハンドラの追加および削除にはこのインスタンス変数を使用することで回避できます。

#import('dart:html');

class Example {
  Element element;
  Function mouseOverHandler;
  Function mouseOutHandler;
  Example(): element = document.query('#target') {
    mouseOverHandler = handleMouseOver;
    mouseOutHandler = handleMouseOut;
  }
  void run() {
    element.on.mouseOver.add(mouseOverHandler);
    element.on.mouseOut.add(mouseOutHandler);
    document.on.click.add(clickHandler);
  }
  handleMouseOver(MouseEvent event) => element.innerHTML = 'dart';
  handleMouseOut(MouseEvent event) => element.innerHTML = 'world';
  clickHandler(MouseEvent event) {
    element.on.mouseOver.remove(mouseOverHandler);
    element.on.mouseOut.remove(mouseOutHandler);
  }
}

void main() {
  document.query('#status').innerHTML = 'Hello, <span id="target">world</span>!';
  new Example().run();
}

この問題はMapやSetの実装に由来しているようです。今後のDart SDKのリリースで修正されることでしょう。(^^)