在javascript中创建嵌套dom节点时遇到问题

时间:2010-11-17 15:11:04

标签: javascript dom nested nodes appendchild

我有一个函数将对象作为参数,并使用对象的结构来创建嵌套的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-structure的一些指示,这对你也有帮助!

3 个答案:

答案 0 :(得分:2)

您的“创建”功能必须以递归方式编写。

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

  1. 找到“tag”属性并创建一个新元素
  2. 为元素提供元素的“id”值(取自数据)
  3. 对于“children”中的每个元素,创建一个节点并将其追加
  4. 因此:

    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>标记为id“screen_name”,<p>标记为id“text”。 (现在我想起来了,除非节点描述有明确的“id”条目,否则你可能想跳过“id”赋值。)

    因此,如果您的页面中有<div>,称为“推文”(使用您的示例,但如果是这样,您肯定想要删除我的功能中的“id”设置部分),那么'' d添加如下结果:

    var createdNodes = create(nodes), tweets = document.getElementById('tweets');
    
    for (var eindex = 0; eindex < createdNodes.length; ++eindex)
      tweets.appendChild(createdNodes[eindex]);
    

答案 1 :(得分: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")); 

答案 2 :(得分:-1)

以前一个答案为基础: 我认为你仍然需要创建你想要追加的元素:

  

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);  
    };  
};