イベントハンドラ

引き続きJavaScriptの勉強。今日はイベントの扱いに関していろいろ調べた。


JavaScriptではユーザイベントに対して処理を定義できる。
DOM要素に対してコールバック関数を割り当てるプロパティをイベントハンドラプロパティと呼ぶとのこと。


主なイベントハンドラ
・onclick - マウスが要素の領域内でクリックされたとき
・onmouseover - マウスが要素の領域に最初に入ったとき
・onmouseout - マウスが要素の領域から出たとき
・onmousemove - マウスが要素の領域を移動するたびに
・onkeypress - キーボードのキーが押されたとき
・onfocus - 要素がフォーカスされる
・onblur - 要素がフォーカスを失う

例えば、指定したHTML内の要素がクリックされたら要素内の文字列を書き換えたい場合、

function clicker(elementId, text) {
  this.elm = document.getElementById(elementId);
  this.text = text;
  this.elm.elmObj = this;
  this.elm.onclick = this.clickerHandler;
}
clicker.prototype.clickerHandler = function() {
  var obj = this.elmObj;
  var text = obj.text;
  document.getElementById("content").innerHTML = text;
}
window.onload = function() {
  var aa = new clicker("hoge", "Hello world!");
}

とすれば、hoge要素をクリックするとinnerHTMLが「Hello world!」に書き換えられる。
最初「var obj = this」としてたらtextが「undefined」になって何で!と悩んでたら、どうもclickerオブジェクトじゃなくてid="hoge"のDOM要素がコンテキストオブジェクトになっていた。
何かコンテキストオブジェクトの考え方がまだ良く分かってないや。ここんところもっと勉強する必要あり。


また、イベントモデルを使うことでもDOM要素を操作出来る。
MozillaSafariではaddEventListener()、IEではattachEvent()という関数を使い、イベントコールをプロパティにアタッチさせる。
しかも、これらを使うと複数のイベント処理を1つのDOM要素にアタッチさせることが出来るそうだ。
勉強用に読んでるprototype.jsのソースを見ると、Eventプロパティにobserveというfunctionプロパティを追加している部分があって、そこでは

_observeAndCache: function(element, name, observer, useCapture) {
  if (!this.observers) this.observers = [];
  if (element.addEventListener) {
    this.observers.push([element, name, observer, useCapture]);
    element.addEventListener(name, observer, useCapture);
  } else if (element.attachEvent) {
    this.observers.push([element, name, observer, useCapture]);
    element.attachEvent('on' + name, observer);
  }
},
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
observe: function(element, name, observer, useCapture) {
  var element = $(element);
  useCapture = useCapture || false;
                                                              
  if (name == 'keypress' &&
      (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
      || element.attachEvent))
    name = 'keydown';
                                                              
  this._observeAndCache(element, name, observer, useCapture);
}

としてイベントをアタッチさせるようにしている。あれ、Safariとかはkeypressイベントプロパティじゃなくてkeydownなんだ。
で、observer配列に入れて管理するようにしているのか。
しかしこのaddEventListener()やattachEvent()ではコンテキストオブジェクトの扱いはどこでどうなっているんだろう?
難しい。。。
あと、ソース読んでて気づいたのが、ウィンドウが閉じられるか終了されるタイミングで実行されるEvent.unloadCacheという関数を実行してobserver配列の中身をカラッポにしたり、removeEventListener()かdetachEvent()でイベントコールバックを除去する処理をしているけれど、そこのコメントに「/* prevent memory leaks in IE */」と書かれている。
IEだとイベントアタッチはちゃんと消してあげないとメモリーリークするんですか!気をつけよう。。。


しかし、prototype.jsのソースは綺麗で分かりやすいなぁ。
最初、どうやって勉強したらいいんだろうと思ってネットサーフィンしてたら、各所でprototype.jsのソース見ろ!と書いてあったのもうなづけます。まだまだ理解不足で読めないところたくさんあるけど・・・
何はともあれせっかく勉強したのでどんどんソース書いて実行してみまくる。