JavaScript でネストされた dom ノードを作成する際に問題が発生する
-
25-09-2019 - |
質問
オブジェクトをパラメータとして受け取り、そのオブジェクトの構造を使用してネストされた DOM ノードを作成する関数がありますが、次のエラーが表示されます。
http://new.app/:75NOT_FOUND_ERR: DOM Exception 8: An attempt was made to reference a Node in a context where it does not exist.
私の関数に実行させたいのは、パラメータとして適切なオブジェクトが指定された場合です。例:
var nodes = {
tweet: {
children: {
screen_name: {
tag: "h2"
},
text: {
tag: "p"
}
},
tag: "article"
}
};
次の DOM ノードが作成されます。
<article>
<h2></h2>
<p></p>
</article>
これまでの私の試みは次のとおりです。
function create(obj) {
for(i in obj){
var tmp = document.createElement(obj[i].tag);
if(obj[i].children) {
tmp.appendChild(create(obj[i].children)); /* error */
};
document.getElementById("tweets").appendChild(tmp);
};
};
もう苦労してるよ!
理想的には、最終的には各オブジェクトに子キーを追加するだけでなく、さらに多くの子キーを追加したいと考えています。 tag
, 、 だけでなく id, innerHTML, class
等
どのような方でも大歓迎ですが、次のことをお願いします。確かに フレームワークまたはライブラリ ほんの数行のコードかそれに似たものでこれを行うことができますが、 使わないほうがいいと思います この特定のプロジェクトのために。
答えを簡単に説明していただければ、これがどのように機能するのか、どこで間違ったのかを理解するのに非常に役立ちます。
ありがとう!
注意:関数内の、エラー メッセージが説明している行を変更してマークしました。
以下から変更しました:
mp.appendChild(obj[i].children);
に:
mp.appendChild(create(obj[i].children));
これは、子オブジェクト内のネストされたキーも作成したいためです。 screen_name
子キーがあった場合、それらも作成されます。 ごめん, これで理解していただけたと思います!
私は見ています http://jsperf.com/create-nested-dom-structor いくつかのヒントについては、これも役立つかもしれません。
解決
「作成」関数は再帰的に記述する必要があります。
データからノードを作成するには (一般に)、次のことを行う必要があります。
- 「tag」プロパティを見つけて新しい要素を作成します
- 要素に要素の「id」値を与えます(データから取得)
- 「children」の要素ごとにノードを作成して追加します。
したがって:
function create(elementDescription) {
var nodes = [];
for (var n in elementDescription) {
if (!elementDescription.hasOwnProperty(n)) continue;
var elem = elementDescription[n];
var node = document.createElement(elem.tag);
node.id = n; // optional step
var cnodes = create(elem.children);
for (var c = 0; c < cnodes.length; ++c)
node.appendChild(cnodes[c]);
nodes.push(node);
}
return nodes;
}
これにより、元の「仕様」オブジェクトから作成された文書要素の配列が返されます。したがって、あなたの例から、次のように呼び出すことになります。
var createdNodes = create(nodes);
「createdNodes」は 1 つの要素の配列になります。 <article>
ID「ツイート」のタグ。この要素には 2 つの子があり、 <h2>
ID「screen_name」と <p>
ID「テキスト」のタグ。(今考えてみると、ノードの説明に明示的な "id" エントリなどがないかぎり、"id" の割り当てをスキップした方がよいかもしれません。)
したがって、あなたが持っている場合、 <div>
「tweets」という名前のページ (例を使用しますが、その場合は関数の「id」設定部分を必ず削除する必要があります) に、次のような結果を追加します。
var createdNodes = create(nodes), tweets = document.getElementById('tweets');
for (var eindex = 0; eindex < createdNodes.length; ++eindex)
tweets.appendChild(createdNodes[eindex]);
他のヒント
Iは、要素のリストを受け付ける機能appendList、およびに追加するコンテナを追加しました。うち、私が「つぶやき」に追加を削除部分をより効果的にあなたのコードを分離する機能を作成します。
function create(obj) {
var els = [];
for(i in obj){
var tmp = document.createElement(obj[i].tag);
var children;
if(children = obj[i].children) {
var childEls = create(children);
appendList(childEls, tmp);
}
els.push(tmp);
};
return els;
};
function appendList(list, container){
for(var i = 0, el; el = list[i]; i++){
container.appendChild(el);
}
};
// gets an array of root elements populated with children
var els = create(nodes);
// appends the array to "tweets"
appendList(els, document.getElementById("tweets"));
前の回答のビル: 私はあなたがまだあなたが追記しようとしている要素を作成する必要があると思う。
tmp.appendChild(子供[支柱] .TAG);
タグでなければなりません
tmp.appendChild(のdocument.createElement(子供[支柱] .TAG));
function create(obj) {
for(i in obj){
var tmp = document.createElement(obj[i].tag);
var children;
if(children = obj[i].children) {
for(var prop in children)
tmp.appendChild(document.createElement(children[prop].tag));
}
document.getElementById("tweets").appendChild(tmp);
};
};