A Better Project@はてなダイアリー(インポート版)

基本的にここは更新されません。詳細はaboutへ。

setAttribute メソッドを使用したとき、IEでは簡単にイベントハンドラを設定できない話

過去エントリであるIEでDOMで生成したbutton(input要素)のイベントハンドラ(onClick)が正常に動作しないの続きです。半年前のエントリですが。

この問題に関しては、IE の getAttribute / setAttribute: Days on the Moonでも解説されているのですが、初心者にはさっぱりわかりません。私も過去エントリを書いたときに、上記ページを見つけていたのですが、スクリプトの意味がさっぱりわからず、最近になって、やっとわかりました。以下、私なりに解説します(ただし、エントリタイトルにあるように、setAttributeでイベントハンドラを設定する話限定です)。

setAttribute メソッドでイベントハンドラ(onclickとかonmouseoverとか)を設定しようとするとき、IE以外のブラウザでは、以下で問題ありません。

element.setAttribute("onclick", 'alert("sample1");');

しかし、これでは、IEでは動きません(IE7でも)。
IE の getAttribute / setAttribute: Days on the Moonで示されている解決策は、以下です。

element.setAttribute("onclick", new Function("clickHandler(event);"));

「new Function("clickHandler(event);")」はJavaScript初心者には、さっぱり意味不明です(わかる人にはわかるよという話はおいておいてください。以下、同様)。これはDateオブジェクトを作成するのと同じように、Functionオブジェクトを作成しています。といっても、普通、「today = new Date();」と()の中身を指定して作成したことがない人にとってはさらに意味不明です(私がそうでした)。
JavaScriptでnew演算子を使って、オブジェクトを作成するときには、()内にプロパティの値を指定することはできます。値が数値や変数ならば、引用符(")は不要ですが、文字列のときは、引用符をつける必要があります。これはalertの()内と同じです。
つまり、「new Function("clickHandler(event);")」というのは、"clickHandler(event);"という文字列をプロパティの値に持つFunctionオブジェクトということになります。(2006-10-25追記:「clickHandler(event);」はFunctionの処理を定義しています。JavaScriptのFuctionについてd:id:potappo:20061025で補足しました。)IEでは動かない最初の例に合わせると以下のようになります。

//最初に、イベントハンドラで実行したい関数を定義する。
function MyAlert2(){
     alert("sample2");
}
element.setAttribute("onclick", new Function("MyAlert2();"));

ちなみに、この方法ではIEでしか動かず、ブラウザ判定をして、処理を分岐させる必要が出てきます。もっと簡単な方法はないものか?あります。element.eventプロパティに実行したい関数を代入するという方法を使えば、IEだろうが、Firefoxだろうが、Operaでも動きます。Safariでは確認してませんが、Apple Developer Connection - Dynamic Content with DOM-2 (Part II of II)を読んだ限りは、だいじょうぶのような気がします。以下のように書きます。

var myalert3 = function(){
    alert("sample3");
    }
element.onclick = myalert3;

変数に実行関数を代入してから、その変数を代入した方が直感的にわかりやすいと思うのですが、以下の方法でもできます。ただし、あまり直感的ではない気がします。

function MyAlert4(){
     alert("sample4");
}
//()は不要。ここの部分が直感的ではないと思う。
element.onclick = MyAlert4;

サンプルを上げておきます。番号は本文の番号と対応してます。
結論としては、クロスブラウザ対応を考えたときには、DOMによるイベントハンドラの設定にsetAttribute メソッドは使うべきではないということになると思います。