【问题标题】:Create an unordered list tree from nested object - JavaScript从嵌套对象创建无序列表树 - JavaScript
【发布时间】:2020-08-26 18:39:41
【问题描述】:

我有一个这样的嵌套对象:

const countries = {
  "Europe": {
    "France": {},
    "Spain": {}
  },
  "America": {
    "North": {
      "USA": {},
      "Canada": {}
    },
    "South": {
      "Brazil": {},
      "Argentina": {}
    }
  }
};

我想从中创建一个无序列表,如下所示:

<ul>
  <li>
    Europe:
    <ul>
      <li>France</li>
      <li>Spain</li>
    </ul>
  </li>
  <li>
    America:
    <ul>
      <li>
        North:
        <ul>
          <li>USA</li>
          <li>Canada</li>
        </ul>
      </li>
      <li>
        South:
        <ul>
          <li>Brazil</li>
          <li>Argentina</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

而且它最后不应该有任何空列表。

到目前为止,我尝试了这种递归方法,但它只返回一个包含 2 个项目的列表[object Object]

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>data tree</title>
  </head>
  <body>
    <div id="container">

    </div>
    <script type="text/javascript">
      const countries = {
        "Europe": {
          "France": {},
          "Spain": {}
        },
        "America": {
          "North": {
            "USA": {},
            "Canada": {}
          },
          "South": {
            "Brazil": {},
            "Argentina": {}
          }
        }
      };

      //Getting the container were I want to put my list
      let container = document.getElementById('container');

      function createTree(container, data) {
        //Recursive function which will create as much lists as I need
        function rec(obj) {
          let list = document.createElement('ul');
          //Looping through the object properties
          for (let item in obj){
            //If the object property is object too
            //And it has its own properties
            //Then create a list ite for it 
            //And put a new list in it with the recursion
            if (Object.keys(obj[item]).length) {
              let listItem = document.createElement('li');
              listItem.textContent += obj[item];
              list.appendChild(listItem);
              rec(obj[item]);
            }
          }
          
          return list;
        }

        //In the end add the list to the container
        container.appendChild(rec(data));
      }

      createTree(container, countries);
    </script>
  </body>
</html>

如果有任何方法可以使用其他方法(如循环或其他任何方法),那也是可以接受的。

提前致谢。

【问题讨论】:

    标签: javascript html list object dom


    【解决方案1】:

    您需要在每次迭代时分配给创建的li 的内容 - 然后检查关联对象是否有任何键,如果有,则执行递归调用:

    const countries = {
      "Europe": {
        "France": {},
        "Spain": {}
      },
      "America": {
        "North": {
          "USA": {},
          "Canada": {}
        },
        "South": {
          "Brazil": {},
          "Argentina": {}
        }
      }
    };
    
    function createTree(container, data) {
      const ul = container.appendChild(document.createElement('ul'));
      for (const [key, val] of Object.entries(data)) {
        const li = ul.appendChild(document.createElement('li'));
        li.textContent = key;
        if (Object.keys(val).length) {
          createTree(li, val);
        }
      }
    }
    
    createTree(document.getElementById('container'), countries);
    <div id="container">
    
    </div>

    我想如果你真的想要,你可以使用 DocumentFragment:

    const countries = {
      "Europe": {
        "France": {},
        "Spain": {}
      },
      "America": {
        "North": {
          "USA": {},
          "Canada": {}
        },
        "South": {
          "Brazil": {},
          "Argentina": {}
        }
      }
    };
    
    function createTree(container, data) {
      const ul = container.appendChild(document.createElement('ul'));
      for (const [key, val] of Object.entries(data)) {
        const li = ul.appendChild(document.createElement('li'));
        li.textContent = key;
        if (Object.keys(val).length) {
          createTree(li, val);
        }
      }
    }
    
    const frag = document.createDocumentFragment();
    createTree(frag, countries);
    document.getElementById('container').appendChild(frag);
    <div id="container">
    
    </div>

    【讨论】:

    • 如果性能不是问题,这可能就可以了。但是,如果是,在我们处理完对象后,是否值得考虑使用文档片段或只是一个普通的旧 innerHTML
    • 除非确实有数以万计的节点,否则这无关紧要。在 99% 的情况下,性能不是问题——最好专注于干净、简短、可读的代码。无论如何,浏览器只会在所有 Javascript 完全完成后重新绘制。
    • 看来我的方法是对的,但我走得太远了,这对我来说非常困难。非常感谢,它看起来更清晰易读!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多