简体   繁体   English

在JavaScript中创建嵌套dom节点时遇到麻烦

[英]trouble creating nested dom nodes in javascript

I've a function that takes an object as a parameter, and uses the structure of the object to create nested DOM nodes, but I receive the following error: 我有一个将对象作为参数的函数,并使用对象的结构来创建嵌套的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.

What I would like my function to do, is, when supplied with a suitable object as a parameter, example: 我希望函数执行的操作是,在将适当的对象作为参数提供时,例如:

var nodes = {
    tweet: {
        children: {
            screen_name: {
                tag: "h2"
            },
            text: {
                tag: "p"
            }
        },
        tag: "article"
    }
};

It would create the following DOM nodes: 它将创建以下DOM节点:

<article>
    <h2></h2>
    <p></p>
</article>

Here is my attempt so far: 到目前为止,这是我的尝试:

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

I'm already struggling! 我已经在挣扎了!

Ideally I'd like to eventually add more child key's to each object, not just tag , but also id, innerHTML, class etc. 理想情况下,我想最终为每个对象添加更多的子键,不仅是tag ,还包括id, innerHTML, class等。

Any hel would be much appreciated, though please: I'm sure a framework or library could do this for me in just a few lines of code, or something similar, but I'd prefer not to use one for this particular project. 不过,请您不胜感激:我敢肯定,只要几行代码或类似的代码, 框架或库就可以为我做到这一点,但是我不希望在特定项目中使用它

If you could briefly explain your answers too it'd really help me learn how this all works, and where I went wrong! 如果您也可以简短地解释您的答案,那将真的帮助我了解这一切的原理以及我出了什么问题!

Thank you! 谢谢!

NB: I've changed and marked the line in my function that the error message is talking about. 注意:我已经更改并标记了错误消息中正在谈论的函数中的行。

I changed it from: 我将其更改为:

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

to: 至:

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

This is because I want any nested keys in the children object to also be created, so screen_name had a children key, they too would be created. 这是因为我希望在子对象中也创建任何嵌套键,所以screen_name有一个子键,它们也会被创建。 Sorry , I hope you can understand this! 对不起 ,希望您能理解!

I'm looking at http://jsperf.com/create-nested-dom-structure for some pointers, this may help you too! 我正在寻找一些指针的http://jsperf.com/create-nested-dom-structure ,这也可能对您有所帮助!

Your "create" function is going to have to be written recursively. 您的“创建”功能将必须递归编写。

To create a node from your data (in general), you need to: 要根据数据创建节点(通常),您需要:

  1. Find the "tag" property and create a new element 找到“标签”属性并创建一个新元素
  2. Give the element the "id" value of the element (taken from the data) 为元素提供元素的“ id”值(从数据中获取)
  3. For each element in "children", make a node and append it 对于“子级”中的每个元素,制作一个节点并将其附加

Thus: 从而:

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

That will return an array of document elements created from the original "specification" object. 这将返回从原始“规范”对象创建的文档元素数组。 Thus from your example, you'd call: 因此,从您的示例中,您可以调用:

var createdNodes = create(nodes);

and "createdNodes" would be an array of one element, an <article> tag with id "tweets". 和“ createdNodes”将是一个元素的数组,一个ID为“ tweets”的<article>标签。 That element would have two children, an <h2> tag with id "screen_name" and a <p> tag with id "text". 该元素将有两个孩子,一个ID为“ screen_name”的<h2>标记和一个ID为“ text”的<p>标记。 (Now that I think of it, you might want to skip the "id" assignment unless the node description has an explicit "id" entry, or something.) (现在我想到了,除非节点描述中有一个明确的“ id”条目或其他内容,否则您可能要跳过“ id”分配。)

Thus if you have a <div> in your page called "tweets" (to use your example, though if so you'd definitely want to cut out the "id" setting part of my function), you'd add the results like this: 因此,如果您的页面中有一个名为“ tweets”的<div> (以您的示例为例,尽管如此,您肯定希望删除函数的“ id”设置部分),则需要添加如下结果这个:

var createdNodes = create(nodes), tweets = document.getElementById('tweets');

for (var eindex = 0; eindex < createdNodes.length; ++eindex)
  tweets.appendChild(createdNodes[eindex]);

I added a function appendList that accepts a list of elements, and the container to append to. 我添加了一个函数appendList,它接受元素列表以及要附加到的容器。 I removed the append to "tweets" part out of the create function to more effectively separate your code. 我从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")); 

Building on the previous answer: I think you still need to create the element you're trying to append: 基于先前的答案:我认为您仍然需要创建要添加的元素:

tmp.appendChild(children[prop].tag); tmp.appendChild(儿童[丙] .TAG);

should be 应该

tmp.appendChild(document.createElement(children[prop].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);  
    };  
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM