Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

innerHTMLのeventに関する罠

innerHTMLの罠を紹介します。
addEventListenerにてtagにeventハンドラを追加している場合、
そのタグの中身をinnerHTMLを使って書き換えを行うと、eventが利用できなくなります。

sampleコード

<html>
<script>
var init = function() {
    var sample = document.getElementById( 'child_id' );
    sample.addEventListener( 'mousedown', down, false );
}

var down = function() {
    alert( 'mouse down' );
}

var replaceHTML = function() {
    var parent = document.getElementById( 'parent_id' );
    var tmp = parent.innerHTML;
    parent.innerHTML = tmp;
}

</script>
<body onload="init();">
<div id="parent_id">
<div id="child_id">div sample</div>
</div>
<input type="button" value="push" onclick="replaceHTML();">
</body>
</html>

sampleコードの中ではparent_id,child_idが入れ子の状態になっています。
parent_idのinnerHTMLに元々のhtmlをそのまま代入しているだけなのですが、
child_idのeventが失われてしまいます。innerHTMLの値を書き換える場合は注意が必要です。

回避策

必要な要素のみ書き換えを行うようにします。
上の場合ですと、child_idのinnerHTMLだけを書き換えます。
Safariでは正常動作確認済みです。

<html>
<script>
var init = function() {
    var child = document.getElementById( 'child_id' );
    child.addEventListener( 'mousedown', down, false );
}

var down = function() {
    alert( 'mouse down' );
}

var replaceHTML = function() {
    var child = document.getElementById( 'child_id' );
    var tmp = child.innerHTML;
    child.innerHTML = tmp;
}

</script>
<body onload="init();">
<div id="parent_id">
<div id="child_id">div sample</div>
</div>
<input type="button" value="push" onclick="replaceHTML();">
</body>
</html>

その他

jQueryのhtml関数を利用しても同様にeventが失われる結果になります。
以下はjQueryを利用した場合のサンプルコードになります。

<html>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.js" ></script>
<script>
var init = function() {
    var child = $( '#child_id' );
    child.mousedown(function(){
        alert( 'mouse down' );   
    });
}

var replaceHTML = function() {
    //var parent = document.getElementById( 'parent_id' );
    var parent = $( '#parent_id' );
    var tmp = parent.html();
    parent.html( tmp );
}

</script>
<body onload="init();">
<div id="parent_id">
<div id="child_id">div sample</div>
</div>
<input type="button" value="push" onclick="replaceHTML();">
</body>
</html>

お願い

※firstChildなどを使ってDOM操作すれば以下の問題も解決出来ますね。
子nodeのidが取れれば上の解決策で対応できるのですが、子nodeのidが取れない場合どうすれば良いでしょうか。Eventが引き継げるコードさえかければ大丈夫なのですが、方法が見つかりません。どなたかご存じの方ご指摘いただけると助かります。