简体   繁体   English

将对象数组渲染为树

[英]Render array of objects as tree

I have an array of objects in which each element contains a string representing its position in a tree structure. 我有一个对象数组,其中每个元素都包含一个表示其在树形结构中位置的字符串。 What would be a simple way to generate a tree view (using basic ul / li tags for example) based on that data? 根据该数据生成树视图(例如,使用基本的ul / li标签)的简单方法是什么?

The depth of the tree structure isn't known beforehand so probably recursion would be the solution? 事先不知道树结构的深度,因此解决方案可能是递归吗?

I'm using React but I guess the question isn't really React-specific so generic JS or even pseudo-code would help a lot. 我正在使用React,但我想这个问题并不是特定于React的,因此通用JS甚至伪代码都会有很大帮助。

Example data: 示例数据:

[
    {
        "name":  "banana",
        "path": "food.healthy.fruit",
        // ... may contain other parameters
    },
    {
        "name":  "apple",
        "path": "food.healthy.fruit"
    }
    {
        "name":  "carrot",
        "path": "food.healthy.vegetable"
    },
    {
        "name":  "bread",
        "path": "food"
    },
    {
        "name":  "burger"
        "path": "food.unhealthy"
    },
    {
        "name":  "hotdog"
        "path": "food.unhealthy"
    },
    {
        "name": "germany",
        "path": "country.europe"
    },
    {
        "name": "china",
        "path": "country.asia"
    }
]

Desired result: 所需结果:

<ul>
    <li>
    food
    <ul>
        <li>bread</li>
        <li>healthy
        <ul>
            <li>
            fruit
            <ul>
                <li>apple</li>
                <li>banana</li>
            </ul>
            </li>
            <li>
            vegetable
            <ul>
                <li>carrot</li>
            </ul>
            </li>
        </ul>
        </li>
        <li>
        unhealthy
        <ul>
            <li>burger</li>
            <li>hotdog</li>
        </ul>
        </li>
    </ul>
    </li>
    <li>
    country
    <ul>
        <li>
        europe
        <ul>
            <li>germany</li>
        </ul>
        </li>
        <li>
        asia
        <ul>
            <li>china</li>
        </ul>
        </li>
    </ul>
    </li>
</ul>
  • food 餐饮
    • bread 面包
    • healthy 健康
      • fruit 水果
        • apple 苹果
        • banana 香蕉
      • vegetable 蔬菜
        • carrot 胡萝卜
    • unhealthy 不良
      • burger 汉堡包
      • hotdog 热狗
  • country 国家
    • europe 欧洲
      • germany 德国
    • asia 亚洲
      • china 中国

Group by path at first. 首先按路径分组。

You can do this by iterating through the source data and split path for each item by dot symbol. 您可以通过遍历源数据并使用点符号分隔每个项目的路径来实现此目的。 Then store each item in a object by keys like this 然后通过这样的键将每个项目存储在对象中

store[country] = store[country] || {}
store[country][europe] = store[country][europe] || []
store[country][europe].push(germany)

Then get all the keys of object at root level and recursivly render all of the items. 然后在根级别获取对象的所有键,然后递归渲染所有项目。 Here is some pseudo-code: 这是一些伪代码:

function render(store){

    let keys = Object.keys(store)

    let ul = document.createElement('ul')

    for (var i = 0; i < keys.length; i++){

      let key = keys[i]

      if (typeof store[key] === 'object') {

        let li = document.createElement('li')

        //create a branch, return it with our render function and append to current level
        li.appendChild(render(store[key]))

      } else {

         // create html presentation for all items under the current key

         let li = document.createElement('li')

      }

       ul.appendChild(li)

    } 

    return ul

}

First of all, you need to restructure data into nested groups. 首先,您需要将数据重组为嵌套组。 Here is how you can reduce your array to necessary structure: 这是将数组简化为必要结构的方法:

const tree = data.reduce(function(prev, curr) {
  const branches = curr.path.split('.')
  let branch = prev
  let branchName

  while (branches.length) {
    branchName = branches.shift()
    let rootIndex = branch.length ? branch.findIndex(el => el.name === branchName) : -1

    if (rootIndex === -1) {
      let newBranch = {
        name: branchName,
        children: []
      }
      branch = branch[branch.push(newBranch) - 1].children
    } else {
      branch = branch[rootIndex].children
    }

    if (branches.length === 0) {
      branch.push({
        name: curr.name
      })
    }
  }

  return prev
}, [])

It will give you array similar to this: 它将为您提供类似于以下的数组:

[
  {
    name: 'food',
    children: [
      {
        name: 'bread'
      },
      {
        name: 'healthy',
        children: [
          {
            name: 'fruit',
            children: [
              {name: 'bannana'},
              {name: 'apple'}
            ]
          }
        ]
      }
    ]
  },
  {
    name: 'country',
    children: [
      // ...
    ]
  }
]

After that, it's easy to create Tree component that would recursively render branches: 之后,很容易创建将递归呈现分支的Tree组件:

const Tree = (props) => (
  <ul>
    {props.data.map((branch, index) => (
      <li key={index}>
        {branch.name}
        {branch.children && (
          <Tree data={branch.children} />  
        )}
      </li>
    ))}
  </ul>  
)

Demo . 演示 Check the demo below. 查看下面的演示。

 const data = [{ "name": "banana", "path": "food.healthy.fruit" }, { "name": "apple", "path": "food.healthy.fruit" }, { "name": "carrot", "path": "food.healthy.vegetable" }, { "name": "bread", "path": "food" }, { "name": "burger", "path": "food.unhealthy" }, { "name": "hotdog", "path": "food.unhealthy" }, { "name": "germany", "path": "country.europe" }, { "name": "china", "path": "country.asia" }] const tree = data.reduce(function(prev, curr) { const branches = curr.path.split('.') let branch = prev let branchName while (branches.length) { branchName = branches.shift() let rootIndex = branch.length ? branch.findIndex(el => el.name === branchName) : -1 if (rootIndex === -1) { let newBranch = { name: branchName, children: [] } branch = branch[branch.push(newBranch) - 1].children } else { branch = branch[rootIndex].children } if (branches.length === 0) { branch.push({ name: curr.name }) } } return prev }, []) const Tree = (props) => ( <ul> {props.data.map((branch, index) => ( <li key={index}> {branch.name} {branch.children && ( <Tree data={branch.children} /> )} </li> ))} </ul> ) ReactDOM.render( <Tree data={tree} />, document.getElementById('demo') ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="demo"></div> 

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

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