スポンサーリンク

JavaScriptの動かないコード (中級編) innerHTMLを追記するとイベントハンドラが消える


以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)


やりたい事:

  • 「追加」ボタンを押すと,「メッセージ表示」ボタンが追加される。
  • どの「メッセージ表示」ボタンを押しても,メッセージが表示される。
<body>


<input type="button" onclick="f()" value="ボタンを追加する">
<br>
<div id="hoge"><input type="button" id="btn1" value="メッセージ表示"></div>


<style type="text/css">
.blue_btn{
  background-color : #ccccff;
  margin : 20px;
}
</style>


<script language="JavaScript">

// イベントを設定
document.getElementById( "btn1" ).onclick = function(){ alert("クリックされました。"); };
var i = 2;

// CSSを設定
document.getElementById( "btn1" ).setAttribute( "class", "blue_btn" );


// 内容を追加
function f(){
	var new_id = "btn" + i;
	
	// HTMLを追加
	hoge.innerHTML += '<input type="button" id="' + new_id + '" class="blue_btn" value="メッセージ表示">';
	
	// イベントを設定
	document.getElementById( new_id ).onclick = function(){ alert("クリックされました。"); };

	// CSSを設定
	document.getElementById( new_id ).setAttribute( "class", "blue_btn" );
	
	i ++;
}

</script>


</body>





答え


発生する不具合


最後に追加されたボタンしか,メッセージ表示できない。

以前からあったボタンを押しても無反応になる。


理由

innerHTMLを追加すると,「元からあるHTML内」のオブジェクトが持っていたメソッドは消えてしまう。

[javascript,prototype]innerHTMLに +=(文字列結合)するのはよろしくないみたい
http://www.greenspace.info/mt/2007/02...

なお,CSSのクラス指定などプロパティは消えないで引き継がれる。

回避策

  • タグの中にonclick=みたいに属性として書いておけば,innerHTML上書き時にもイベントハンドラは保たれる。
  • または,innerHTML追記ではなく,DOM要素をcreateElement()してappendChild()するほうが安全。


innerHTML系の罠の多さには参る。