将树状对象渲染为HTML元素

3

我有一些关于这个问题的困难。我想要根据树形结构渲染一些html元素。例如,这个javascript树形对象:

let htmlTree = {
    id: "a",
    children: [{
        id: "b",
        children: []
    }, {
        id: "c",
        children: [{
            id: "d",
            children: []
        }]
    }]
};

应该输出类似于这样的字符串:
<a>
    <b>
    </b>
    <c>
        <d></d>
    </c>
</a>

我尝试使用广度优先遍历(迭代)树对象,但在实际中遇到了一些问题,无法确定何时应用嵌套情况下元素的关闭标签。非常感谢您的帮助,我一整天都被卡住了 :(


为什么不尝试深度优先遍历呢?这个解决方案非常自然。 - BaseZen
你需要结果中的换行符吗? - markasoftware
4个回答

2

我知道您已经有了一个答案,但是我认为这对讨论是有帮助的。您可以使用Javascript dom函数来完成繁重的工作。在更复杂的情况下,这可能非常有价值。

function create_node(obj){
    var node = document.createElement(obj.id);
    for (var i in obj.children) {
        node.appendChild(create_node(obj.children[i]));
    }
    return node;
}
console.log(create_node({id:'root',children:[htmlTree]}).innerHTML);

JSFiddle: http://jsfiddle.net/trex005/8gxe7z3b/

注意: 为了获取完整的HTML代码,我将其包装在一个父节点中,以便使用innerHTML方法,因为没有跨浏览器的方法可以获取outerHTML。


1
这将使字符串没有换行符...我使用var而不是let以提高兼容性。
var outputStr='';
function checkChildren(parentObj){
    outputStr+='<'+parentObj.id+'>';
    if(parentObj.children.length>0)
        parentObj.children.forEach(checkChildren);
    outputStr+='</'+parentObj.id+'>';
}
checkChildren(htmlTree);

如果需要换行,修改起来很容易。这里是一个可用的jsfiddle示例


我试图通过广度优先树遍历使事情变得过于复杂化了。非常感谢。 - thunderousNinja

1
我花了很多时间做类似这样的事情,在我的努力中,我建立了一个非常高效的框架,采用面向对象的方法,稍微复杂一些,但它可以快速开发,并具有像API一样的接口。
  1. 以代码中所示的简单语法声明JSON对象
  2. 声明一个特定于对象的create方法(Form.prototype.create),并指定如何构建对象。
  3. 然后只需调用Build()函数并将JSON对象作为参数传递。 例如--- Build(signin)

//CODE

    <!DOCTYPE html>
    <html>
    <head>
    <script>
    //SIMPLE JSON SYNTAX
    var signin = [
        {"container":{"element": "aside", "attributes": {"id":"overlay","class":"overlay1","onclick":"Destroy(event);"}}},
        {"form":{"element": "form", "attributes": {"id":"form"}}},
        {"msg":{"element": "mark", "attributes": {"id":"form-msg"}}},
        {"ipt1":{"element": "input", "attributes": {"type":"email","placeholder":"email","name":"email"}}},
        {"ipt2":{"element": "input", "attributes": {"type":"password","placeholder":"password","name":"password"}}},
        {"ipt3":{"element": "input", "attributes": {"type":"button","value":"Sign In","class":"form-btn btn-blue", "data-url":"/core/signin.php","onclick":"Submit(this);"}}},
        {"ipt4":{"element": "input", "attributes": {"type":"button","value":"Account Recovery","class":"form-btn btn-black","data-form":"recover","onclick":"Build(recover)"}}}
    ];

    //MAIN BUILD FUNCTION
    function Build(obj){
        //CREATE NEW FORM OBJECT WITH DYNAMIC PROP AND VALUES
        var form = Form.new(obj);

        //CREATE HTML ELEMENTS AND APPEND ITS ATTRIBUTES 
        form.assemble();

        //DEFINE HOW YOU WANT THE OBJECT TO BE ASSEMBLED
        form.create();
    }

   //DYNAMIC FORM CONSTRUCTOR
    function Form(){
        for(var i=0; i < arguments.length; i++){
            var key = Object.keys(arguments[i]);
            this[key] = arguments[i][key];
        }   
    }
   //FORM OBJECT CONSTRUCTOR METHOD (CREATE)
    Form.prototype.create = function(){
        var inpts = Object.keys(this).splice(3);
        var container = document.body.appendChild(this.container);
        var form = container.appendChild(this.form);
        container.appendChild(this.msg);
        for(i=0; i < inpts.length; i++){
            form.appendChild(this[inpts[i]]);
        }           
    }
    //GLOBAL FUNCTION METHOD (NEW)
    Function.prototype.new = function (args) {
        var Fake = Object.create(this.prototype);
        this.apply(Fake, args);
        return Fake;
    };
    //GLOBAL OBJECT METHOD (ASSEMBLE)
    Object.prototype.assemble = function(){
        for(key in this){
            if(this.hasOwnProperty(key)){
                var element = document.createElement(this[key].element);
                var attributes = this[key].attributes;
                for(prop in attributes){
                    if(attributes.hasOwnProperty(prop)){
                        element.setAttribute(prop, attributes[prop]);
                        this[key] = element;
                    }
                }   
            }
        }       
    }
    </script>
    </head>
    <body></body>
    </html>

哇,这真的很酷。我一定会试试看。看起来非常有用! - thunderousNinja
1
@unknown 谢谢,是的,需要很多思考才能想出这种方法,而且你甚至可以在Build()函数中添加一个switch语句来读取obj参数,然后根据obj创建不同的对象。对于任何对象,你都调用了相同的(new)和(assemble)函数,它们是全局的,然后只需指定(create),这使你可以将其附加到文档中的任何位置,并按照你想要附加元素的顺序进行附加。 - Jordan Davis

1
尝试这个。
var treeRendrer = function(treeObj,parent){
      if(treeObj && treeObj.hasOwnProperty("id")){
         parent.appendChild(document.createElement(treeObj["id"]))
      }
      if(treeObj && treeObj.hasOwnProperty("children")){
         treeObj.children.forEach(function(childObj){
            treeRendrer(childObj, parent.firstChild)
         });
      } 
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接