2

我有一个将对象作为参数的函数,并使用对象的结构来创建嵌套的 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等等。

任何 hel 将不胜感激,但请:我确信框架或库可以在几行代码或类似的代码中为我完成此操作,但我不希望在这个特定项目中使用一个。

如果您也可以简要解释您的答案,那真的会帮助我了解这一切是如何运作的,以及我哪里出错了!

谢谢!

注意:我已经更改并标记了我的函数中错误消息所涉及的行。

我将其更改为:

mp.appendChild(obj[i].children);

至:

mp.appendChild(create(obj[i].children));

这是因为我希望子对象中的任何嵌套键也被创建,所以screen_name如果有一个子键,它们也会被创建。对不起,我希望你能明白这一点!

我正在查看http://jsperf.com/create-nested-dom-structure以获取一些指针,这也可能对您有所帮助!

4

3 回答 3

2

您的“创建”函数将不得不递归编写。

要从您的数据创建节点(通常),您需要:

  1. 找到“tag”属性并创建一个新元素
  2. 为元素赋予元素的“id”值(取自数据)
  3. 对于“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”将是一个包含一个元素的数组,一个<article>ID 为“tweets”的标签。该元素将有两个子元素,一个<h2>标识为“screen_name”的<p>标签和一个标识为“text”的标签。(现在我想到了,你可能想跳过“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]);
于 2010-11-17T15:44:46.743 回答
0

我添加了一个函数 appendList,它接受元素列表和要追加到的容器。我从 create 函数中删除了对“tweets”部分的附加,以更有效地分离您的代码。

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")); 
于 2010-11-17T15:30:39.867 回答
-1

基于上一个答案:我认为您仍然需要创建要附加的元素:

tmp.appendChild(children[prop].tag);

应该

tmp.appendChild(document.createElement(children[prop].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);  
    };  
};
于 2010-11-17T15:45:05.093 回答