innerHTMLでdocument.writeする - その1
前回のエントリの続きです。defer属性指定しただけではdocument.writeしたときに順番が狂う。foo fooなら foo foo barと表示される。ノードツリーが完成した後にdocument.writeすると大変なことになるしなかなか利用しづらい面もあって、以下のようなコード書いてみました。(IE6、Fx2、Opera8で確認)
ソース
<html> <head> <script> /** * parent.insertBefore(node, target)は * <parent> <target /> </parent>に対して<target>の先頭にnodeを追加していくDOMメソッド。 * 何回か実行すると以下のようになる。 * <parent> <node1 /> <node2 /> <target /> </parent> */ function write(parent, target) { return function(str){ parent.insertBefore(document.createTextNode(str), target); }; }; function sample() { var div = document.getElementById('div'); div.innerHTML = 'foo<script id="script">document.write("bar");document.write("foo")<'+'/script>bar'; var script = document.getElementById('script'); // オリジナルのdocument.writeを保存 var original = document.write; // document.writeに上記のwriteを代入 document.write = write(div, script); // script.textの内容を実行します。 eval(script.text); // document.writeを元に戻す。 document.write = original; } </script> </head> <body onload="sample();"> <div id="div"></div> </body> </html>
実行結果
foo bar foo bar
解説
innerHTMLで<script>を挿入したときはスクリプトの評価はされないがDOMノードには追加されています。そんなんで、id属性とかDOMノード列挙で挿入したスクリプトを取得できるので挿入したソースをtextプロパティで取得(OperaではinnerHTMLで取得できないから。textを利用。)それをevalすればスクリプトは実行されます。
ただdocument.writeとかあると順番が狂うのでdocument.writeをハックしてごにょごにょしてあげれば順番通りにTextノードが追加されてオーケー!
とまぁ
evalとかしてますし汎用的じゃなくてかなりナンセンスです。いつかきっと凄腕のハッカさんが凄いコードを書いてくれるはず。XMLHttpRequestで取得したHTMLをそのままinnerHTMLに挿入してそこにあるscriptもついでに実行したい場合には役に立つはずです。