心魅 - cocoromi -

半角スペース時々全角

Document Object Model Events

ブラウザJSでアプリケーションのロジックをつくろうとしていて、どうもObserver Patternになりそうなので、カスタムイベントを扱う方法を調べている。


取り合えずW3Cのドキュメントから。Level3はDraft。
http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/
http://www.w3.org/TR/2011/WD-DOM-Level-3-Events-20110531/


参考にしたのはこちら。
javascriptのカスタムイベントを作ろう!
http://d.hatena.ne.jp/shim0mura/20111224/1324735206


やりたい事

  1. EventTargetオブジェクトのdispatchEventしたいから、EventTargetを作りたい
  2. Eventオブジェクトを拡張したい
  3. 拡張したEventオブジェクトをイベントハンドラで処理したい

3はclickなんかのハンドリングと変わらないので気にしない。

EventTargetを操作するには

イベントが拡張できたとしても発火出来なかったら何も意味ない!
なのでまずは発火つまりdispatchを行えるのかを調べた。


これに関してはEventTargetがインターフェースとして定義されているのだが、
Interface EventTarget (introduced in DOM Level 2)で書かれているようにHTMLのノードとして実装されている模様。

The EventTarget interface is implemented by all Nodes in an implementation which supports the DOM Event Model.

DOM Event Modelをサポートしている実装(訳者注ブラウザのこと)では全てのノードがEventTargetインターフェースを実装します。


ちなみに、定義はこんな感じ。

// Introduced in DOM Level 2:
interface EventTarget {
  void               addEventListener(in DOMString type, 
                                      in EventListener listener, 
                                      in boolean useCapture);
  void               removeEventListener(in DOMString type, 
                                         in EventListener listener, 
                                         in boolean useCapture);
  boolean            dispatchEvent(in Event evt)
                                        raises(EventException);
};


アプリケーションロジックとしてのイベントを扱いたいので、これを使うのはスマートでは無い。
使うんだけど。



Eventオブジェクトを拡張する

Level2だと微妙だったのだが、Level3だとCustomEventというインターフェースが定義されている。

The CustomEvent interface is the recommended interface for application-specific event types. Unlike the Event interface, it allows applications to provide contextual information about the event type. Application-specific event types should use a prefix string on the event type name to avoid clashes with future general-purpose event types.


To create an instance of the CustomEvent interface, use the DocumentEvent.createEvent("CustomEvent") method call.

アプリケーションで定義される種類のイベントはCustomEventを使って実装するといいでしょう。
Eventインターフェースとは違い、アプリケーションがイベントについての情報を提供することができます。
アプリケーションで定義されるイベントの名前にはプリフィクスをつけましょう。一般的なイベント名の場合、将来的な名前の衝突を避けることが出来ます。


インスタンスの生成にはDocumentEvent.createEvent("CustomEvent")を呼び出します。


ってなわけで、createEventの引数に"CustomEvent"を渡せば、アプリケーションレベルのイベントを定義することができそうである。



実装してみた

  • document.createEvent("CustomEvent")
    • 引数間違えるとエラー出るよ( ex: Error: NOT_SUPPORTED_ERR: DOM Exception 9 )
  • evt.initCustomEvent コンストラクタが提供されてないので、メソッドで初期化します
    • 引数は( イベント種 , バブルアップするか , キャンセル出来るか )
  • document.createElement前述の通り、EventTargetはDOMのエレメントとしてしか提供されていないので、適当な要素をつくる

https://github.com/umezo/umezone/blob/master/javascript/samples/event/index.html

まとめ

ブラウザJSでも組み込みのイベントの仕組みを使ってObserverパターンを実装できそう。
その為にdocument.createEventやinitCustomEventを使う。
document経由でイベントの操作するのがちょっと、おかしい気がするけどしょうが無い。