読者です 読者をやめる 読者になる 読者になる

tumblr

tumblr(タンブラー)は、メディアミックスブログサービス。ブログとミニブログ、そしてソーシャルブックマークを統合したマイクロブログサービスである。アメリカのDavidville.inc(現: Tumblr, Inc.)により2007年3月1日にサービスが開始された。

javascriptのカスタムイベントを作ろう!

Javascript

デフォルトで用意されているイベントは、基本的にはブラウザがfireすることで要素に登録されたイベントリスナーが呼ばれるわけなんですが、このイベントのfireを開発者側でも行えるワケです。これはテスト用途での使われることが多いみたいです。
というわけでそのイベントのエミュレートと独自イベントの合成を学んだので覚書。サイ本じゃ合成イベントなんて言われてるけど、googleで検索するとカスタムイベントって言われるほうが多いみたい。

おおまかな流れ(IE除く)

  1. イベントオブジェクトの作成
  2. イベントオブジェクトの初期化
  3. イベントのディスパッチ(発火)

という感じ。発火の前にはaddEventListenerで任意の要素に、イベントハンドラを登録する必要があります。

イベントオブジェクトの作成

var event = document.createEvent(type);

引数のtypeはイベントタイプを表します。イベントタイプには、onclickやonkeydownなどの詳細なタイプではなく、DOMLevel2EventsまたはDOMLevel3Eventsのイベントモジュールとして定義される以下の大きな分類を指定します。

  • HTMLEvents(HTML要素に関するイベント、onchange,onfocus,onloadなど)
  • MouseEvents(マウスに関するイベント、onclick,onmousedownなど)
  • MutationEvents(要素の変更に関するイベント、DOMNodeInsertedなど)
  • UIEvents(DOMFocusIn,DOMFocusOutなど、正直よくわからない)


※上記はDOMLevel2Eventの分類です。DOMLevel3EventsではkeybordEventsが入ってきたり、onloadがUIEventsモジュールに入ってたりします。

イベントオブジェクトの初期化

とにかくイベントオブジェクトを作成できたら、そのイベントオブジェクトを初期化します。これもイベントモジュールごとに初期化用メソッドがあるので、それを使用します。ここでイベントハンドラに渡す引数となるイベントオブジェクトを初期化するわけです。

event.initEvent(type, bubbles, cancelable) 


上記はHTMLEventsの初期化メソッドです。typeにはイベントの名前(onfocus,onloadなど)を付けます。もちろん自分の独自の名前だってつけられます。bubblesはイベントを伝蟠させるかどうかのbool値を、cancelableにはpreventDefaultでキャンセルできるかどうかのbool値を指定します。

initEventはHTMLEvents用ですが、MouseEventsの場合はinitMouseEventを、UIEventsの場合はinitUIEventを、MutationEventsにはinitMutationEventを指定します。
上記の各メソッドごとに渡す引数が違ってきます。例えばMouseEventsであれば、イベントハンドラに引数としてMouseEventオブジェクトを渡す際に、screenX,screenYなどの情報が必要になるので、この初期化メソッドにそれらの情報を渡します。

各種イベント初期化メソッドについてはこちら(正直書くの面倒になってきた)
https://developer.mozilla.org/ja/DOM/event.initEvent
https://developer.mozilla.org/en/DOM/event.initUIEvent
https://developer.mozilla.org/en/DOM/event.initMouseEvent

イベントのディスパッチ(発火)

初期化ができたら、イベントを発火させたい要素のdispatchEventメソッドを呼び出します。このとき、このメソッドの引数として、さっき初期化したイベントオブジェクトを渡します。

var elm = document.getElementById("test");
elm.dispatchEvent(event);

あとは通常のイベントフローと同じ。イベントオブジェクト初期化時にわたしたtypeにイベントハンドラが登録されていればそのイベントハンドラが実行されます。


実際にコード書いたほうが流れ分かりやすいかも
"custom_event"というそのまんまのカスタムイベントを作成してみます。

<span id="emulator" style="display:inline-box;border:1px solid black;background:gray">
emulate event
</span>

<script>

var elm = document.getElementById("emulator");


//カスタムイベント(custome_event)にイベントハンドラ登録
elm.addEventListener("custom_event", function(){
  alert("custom event fire!!");
}, false);


//要素クリック時にカスタムイベントを発火させる
elm.addEventListener("click", function(){
  //カスタムイベントの作成・初期化
  var customEvent = document.createEvent("HTMLEvents");
  customEvent.initEvent("custom_event", true, false);
  //fire!!
  this.dispatchEvent(customEvent);
}, false);

</script>

ちょっと待って、addEventListener使ってるってことは…?

そうです!!可愛さ余って憎さ1万倍!みんな大好きInternetExplorerさんはもちろんcreateEventなんてメソッド持ってません!はやく滅びろ!!バルス!!!!

ということでスーパー面倒ですが、IEはcreateEventなどに相当する独自メソッドを使いましょう。*1

IEでのイベントオブジェクトの作成
var event = document.createEventObject();

これでIE(before version9)でもイベントオブジェクトを作成できます。

IEでのイベントのディスパッチ(発火)
var elm = document.getElementById("test");
elm.fireEvent("onclick", event);

これでイベントを発火させることができます。第一引数にはonclick,onloadなどのイベントタイプを、第二引数にはイベントオブジェクトを指定します。
ここで面倒なのは、実はIEではこの方法を使う限りカスタムイベントの作成はできません。上で"custom_event"というカスタムイベントを作成しましたが、それはIEでは出来ないということです。既存のイベントタイプを使うという方法しかありません。IEにおいては、カスタムイベントを作るというよりも、テスト用のイベントエミュレータという位置づけっぽいです。

*1:IE9では上で紹介したinitEventなどをサポートしています