JavaScript DOMツリー中に含まれるスクリプトを実行する

はじめに

エントリにサンプルコードを載せて、ボタンを押したら実行できるようにしたい。同じコードを表示用と実行用で2回書くのはナンセンスなので、DOMツリー中からコードを取得してevalしたい。

簡単じゃね?

俺には未体験ゾーンです。

続きは専用ページで

グローバル名前空間を汚すので、インデックスや月別アーカイブに全文を載せるのは気が引ける。

まずはクリック時にスクリプトを実行するだけ

var exec01 = function() {
alert('Hello, wolrd!');
}


exec

eval化

var exec02 = function() {
var t="alert('Hello, wolrd!');";
eval(t);
}


exec

DOMから取得

getElementByIdでDOMツリーから対象のpreタグを取得。文字列自体は子要素としてテキストになっているので、childNodesの最初の要素の値を取得。

var exec03 = function() {
var t=document.getElementById("code03").childNodes[0].nodeValue;
eval(t);
}


alert("Hello, world!");

exec

IDを指定できるように改良

var exec04 = function(id) {
var t=document.getElementById(id).childNodes[0].nodeValue;
eval(t);
}


alert("Hello, world!");

exec

タグが含まれていると動きません!

childNodes[0]とnodeValueの決め打ちが良くない

alert("Hello, world!");

exec(動作しません)

再起処理で対象ID以下のテキストをすべて取得、連結

var getText06 = function(elem) {
var t='';
var children=elem.childNodes;
for ( var i = 0; i < children.length; i++ ) {
if (children[i].nodeType == 1) { // ELEMENT_NODE
t += getText06(children[i]);
}
else {
t += children[i].nodeValue;
}
}
return t;
}
var show06 = function(id) {
alert(getText06(document.getElementById(id)));
}


alert("Hello, world!");

exec

もっと複雑なDOMでテスト

alert("Hello, world!"); // Comment
alert("Hello, world!");

exec

再びeval化

var getText08 = function(elem) {
var t='';
var children=elem.childNodes;
for ( var i = 0; i < children.length; i++ ) {
if (children[i].nodeType == 1) { // ELEMENT_NODE
t += getText08(children[i]);
}
else {
t += children[i].nodeValue;
}
}
return t;
}
var exec08 = function(id) {
eval(getText08(document.getElementById(id)));
}


alert("Hello, world!"); // Comment

exec

コードをコンパクトに

関数内で関数を宣言してみたり、三項演算子を使ったり。

var exec09 = function(id) {
var getText09 = function(elem) {
var t='';
var children=elem.childNodes;
for ( var i = 0; i < children.length; i++ ) {
t += (children[i].nodeType == 1) ? getText09(children[i]) : children[i].nodeValue;
}
return t;
}
eval(getText09(document.getElementById(id)));
}


alert("Hello, world!"); // Comment

exec

動作テスト

FizzBuzz
(function() {
var t='';
for ( var i = 1; i <= 100; i++ ) {
if ( i % 15 == 0) { t += 'FizzBuzz '; }
else if ( i % 3 == 0 ) { t += 'Fizz '; }
else if ( i % 5 == 0 ) { t += 'Buzz '; }
else { t += i.toString() + ' '; }
}
var result=document.getElementById("result10");
result.innerHTML = t;
})();

exec


フィボナッチ
(function() {
var fibonacci = function(n) {
if (n <= 2) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
var result=document.getElementById("result11");
result.innerHTML = fibonacci(10).toString();
})();

exec


動いてるっぽい

基本は出来たと思う。

おわり

とても勉強になりました。JavaScriptとDOMの連携ってとても面白いですね。JavaScriptにハマっている人たちってこの面白さに惹かれたのだろうと思いました。今後の課題ですが、

  • ID指定するのがめんどい。
    • 直前のコードっぽい要素に対する実行とするのはどうだろう?
    • コードの方に特定のクラス(executableとか)を指定しておいて、ロード時に実行用アンカー要素を追加
  • 見せたいコードと関係ないコード(DOM操作)が混在していてイヤ。
    • 見せたいコードの結果を受け取って、結果出力用要素に書くだけの関数があればよさそう

というのが浮かびました。余計なことかなー、とも思いますので、しばらく考えようと思います。

最後まで読んでいただき、ありがとうございました。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする