以递归方式在ul列表中显示JavaScript对象

时间:2017-04-21 19:06:14

标签: javascript html recursion

我正在尝试以HTML ul列表方式显示JavaScript对象。 该对象表示二叉树,具有以下格式:

{
    "val":2,
    "l":{
        "val":1,
        "l":{},
        "r":{}
    },
    "r":{
        "val":4,
        "l":{},
        "r":{
            "val":5,
            "l":{},
            "r":{}
        }
    }
}

我需要完成的结果是:

<ul>
    <li>
        <a href="#">2</a>
        <ul>
            <li>
                <a href="#">1</a>
            </li>
            <li>
                <a href="#">4</a>
                <ul>
                    <li>
                        <a href="#">5</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

我在这里编写此代码是为了获取结果的相应字符串,但它不会生成正确的结果。

function buildList(data){
    var html = '';
    if(data.val){
        if(data.l){
            html += '<ul>';
            html += buildList(data.l);
        }
        html += '<li>';
        html += '<a href="#">' + data.val + '</a>'
        html += '</li>';
        if(data.r){
            html += buildList(data.r);
            html += '</ul>';
        }
    }

    return html;
}

任何猜测或线索都会受到赞赏。

4 个答案:

答案 0 :(得分:2)

让生活更轻松

这种情况下,一点点的数据抽象是一种低调的方式。如果您尝试在单个函数中处理数据中的所有差异,您将面临单分支if和其他副作用代码的大意大利面。

使用下面的数据抽象,我将复杂的逻辑和条件简化为单个if/else语句。我将逐步逐步完成代码,然后我将它们放在最后的可运行演示中

一厢情愿

我不想考虑(例如)val是{}还是lr具有有效价值 - 这对我来说毫无意义。我想写的是这样的:

const makeTree = ({val, l, r}) => {
  if (val === undefined)
    return []
  else
    return [Node('ul', Node('li', Link('#', val)), ...makeTree(l), ...makeTree(r))]
}

这假设我们有两个构造函数NodeLink。但在我们深入研究之前,我们看到makeTree无论如何都返回一个数组。因此,我们必须提出一个很好的面向用户的功能,以某种方式为我们构建HTML。这将是makeMenu - 所有这一切都需要将根节点从数组中取出并在其上调用.toElem()

const makeMenu = data =>
  makeTree(data)[0].toElem()

这也有助于我们了解我们需要在.toElemNode两种节点类型上使用Link。看,使用一厢情愿的想法很好地构建你的程序,因为你想要的每一步都告诉你你必须构建的下一件事。

NodeLink构造函数

现在让我们点击NodeLink。他们非常直截了当。 Node只是特定type的通用HTML元素,可以将子元素应用于它;请注意,每个孩子也应该有.toElem方法。 Link只需要href和一些text,然后根据相应的属性构建元素。

const Node = (type, ...children) => ({
  toElem: () => {
    const elem = document.createElement(type)
    children.forEach(child => elem.appendChild(child.toElem()))
    return elem
  }
})

const Link = (href, text) => ({
  toElem: () => {
    const elem = document.createElement('a')
    elem.setAttribute('href', href)
    elem.textContent = text
    return elem
  }
})

全部放在一起

&#13;
&#13;
const Node = (type, ...children) => ({
  toElem: () => {
    const elem = document.createElement(type)
    children.forEach(child => elem.appendChild(child.toElem()))
    return elem
  }
})

const Link = (href, text) => ({
  toElem: () => {
    const elem = document.createElement('a')
    elem.setAttribute('href', href)
    elem.textContent = text
    return elem
  }
})

const makeTree = ({val, l, r}) => {
  if (val === undefined)
    return []
  else
    return [Node('ul', Node('li', Link('#', val)), ...makeTree(l), ...makeTree(r))]
}

const makeMenu = data =>
  makeTree(data)[0].toElem()

const data = { "val": 2, "l": { "val": 1, "l": {}, "r": {} }, "r": { "val": 4, "l": {}, "r": { "val": 5, "l": {}, "r": {} } } }

document.body.appendChild(makeMenu(data))
&#13;
&#13;
&#13;

答案 1 :(得分:1)

您可以通过使用所需对象构建DOM节点来使用动态递归方法。

function buildDOM(tree) {
    function buildLI(node) {
        var li = document.createElement('li'),
            a = document.createElement('a');

        a.href = '#';
        a.appendChild(document.createTextNode(node.val));
        li.appendChild(a);
        if (('l' in node) && ('val' in node.l) || ('r' in node) && ('val' in node.r)) {
            li.appendChild(buildDOM(node));
        }
        return li;
    }

    var ul = document.createElement('ul');                

    if (('l' in tree) && ('val' in tree.l)) {
        ul.appendChild(buildLI(tree.l));
    }
    if (('r' in tree) && ('val' in tree.r)) {
        ul.appendChild(buildLI(tree.r));
    }
    return ul;
}

var data = { val: 2, l: { val: 1, l: {}, r: {} }, r: { val: 4, l: {}, r: { val: 5, l: {}, r: {} } } };

document.body.appendChild(buildDOM({ r: data }));  

答案 2 :(得分:0)

你只需稍微重新排列代码即可。这是一个有效的解决方案:

&#13;
&#13;
function buildList(data){
    var html = '';
    if(data.val){
        html += '<ul><li>';
        html += '<a href="#">' + data.val + '</a>'
        html += '</li>';
        if(data.l){
            html += buildList(data.l);
        }
        if(data.r){
            html += buildList(data.r);
            html += '</ul>';
        }
    }

    return html;
}

var resultDiv = document.getElementById('resultDiv');

var testData = 
    {
        "val":2,
        "l":{
            "val":1,
            "l":{},
            "r":{}
        },
        "r":{
            "val":4,
            "l":{},
            "r":{
                "val":5,
                "l":{},
                "r":{}
            }
        }
    };
    
resultDiv.innerHTML = buildList(testData);
&#13;
<p>Actual Result:</p>
<div id="resultDiv">...</div>

<hr>

<p>Desired Result:</p>
<ul>
    <li>
        <a href="#">2</a>
        <ul>
            <li>
                <a href="#">1</a>
            </li>
            <li>
                <a href="#">4</a>
                <ul>
                    <li>
                        <a href="#">5</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>
&#13;
&#13;
&#13;

答案 3 :(得分:0)

var dom = buildList(yourObject);
final(dom);

function buildList(data){
    if(data.val){       
        var currentTag = document.createElement('li');
        var atag = document.createElement('a');
        atag.setAttribute("href", "#");
        atag.innerText = data.val;
        currentTag.appendChild(atag);
        if(JSON.stringify(data.l) != "{}" || JSON.stringify(data.r) != "{}"){           
            var ulTag = document.createElement('ul');
            if(JSON.stringify(data.l) != "{}"){
                ulTag.appendChild( buildList(data.l));
            }
            if(JSON.stringify(data.r) != "{}"){
                ulTag.appendChild( buildList(data.r));
            }
            currentTag.appendChild(ulTag);
        }
    }

    return currentTag;
}

function final(body) {
   body = document.createElement('ul').appendChild(body);
}