我有一个对象数组,其中每个元素都包含一个字符串,表示它在树结构中的位置。基于该数据生成树视图(例如使用基本ul
/ li
标记)的简单方法是什么?
事先不知道树结构的深度,所以可能递归就是解决方案吗?
我正在使用React,但我想这个问题并不是React特有的,所以通用JS甚至伪代码都会有很大的帮助。
示例数据:
[
{
"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"
}
]
期望的结果:
<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>
答案 0 :(得分:0)
首先按路径分组。
您可以通过点符号迭代每个项目的源数据和拆分路径来完成此操作。然后通过像这样的键
将每个项目存储在一个对象中store[country] = store[country] || {}
store[country][europe] = store[country][europe] || []
store[country][europe].push(germany)
然后在根级别获取对象的所有键,并递归渲染所有项目。这是一些伪代码:
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
}
答案 1 :(得分:0)
首先,您需要将数据重组为嵌套组。以下是如何将阵列减少到必要的结构:
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
}, [])
它会给你类似的数组:
[
{
name: 'food',
children: [
{
name: 'bread'
},
{
name: 'healthy',
children: [
{
name: 'fruit',
children: [
{name: 'bannana'},
{name: 'apple'}
]
}
]
}
]
},
{
name: 'country',
children: [
// ...
]
}
]
之后,很容易创建递归渲染分支的Tree
组件:
const Tree = (props) => (
<ul>
{props.data.map((branch, index) => (
<li key={index}>
{branch.name}
{branch.children && (
<Tree data={branch.children} />
)}
</li>
))}
</ul>
)
<强>演示即可。查看下面的演示。
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>