实现树形菜单vue
实现树形菜单的Vue方案
递归组件方案
创建递归组件TreeMenu.vue,通过组件自身嵌套实现无限层级渲染
<template>
<ul>
<li v-for="item in data" :key="item.id">
{{ item.label }}
<TreeMenu v-if="item.children" :data="item.children"/>
</li>
</ul>
</template>
<script>
export default {
name: 'TreeMenu',
props: {
data: Array
}
}
</script>
动态组件方案
使用v-for和条件渲染实现多级菜单
<template>
<div class="tree-menu">
<div
v-for="node in treeData"
:key="node.id"
:style="{ paddingLeft: `${level * 20}px` }"
>
<div @click="toggleExpand(node)">
<span v-if="node.children">{{ node.expanded ? '▼' : '▶' }}</span>
{{ node.label }}
</div>
<TreeMenu
v-if="node.expanded && node.children"
:treeData="node.children"
:level="level + 1"
/>
</div>
</div>
</template>
<script>
export default {
props: {
treeData: Array,
level: {
type: Number,
default: 0
}
},
methods: {
toggleExpand(node) {
this.$set(node, 'expanded', !node.expanded)
}
}
}
</script>
第三方库方案
使用vue-treeselect等成熟组件库
npm install @riophae/vue-treeselect
<template>
<treeselect
v-model="value"
:multiple="true"
:options="options"
/>
</template>
<script>
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
components: { Treeselect },
data() {
return {
value: null,
options: [{
id: 'group',
label: 'Group',
children: [{
id: 'child',
label: 'Child'
}]
}]
}
}
}
</script>
性能优化技巧
添加v-memo指令缓存静态节点
<li
v-for="item in data"
:key="item.id"
v-memo="[item.id, item.label]"
>
{{ item.label }}
</li>
使用虚拟滚动处理大数据量
<template>
<RecycleScroller
:items="flattenData"
:item-size="32"
key-field="id"
>
<template #default="{ item }">
<div :style="{ paddingLeft: `${item.level * 20}px` }">
{{ item.label }}
</div>
</template>
</RecycleScroller>
</template>
数据格式建议
推荐使用标准树形结构
const treeData = [
{
id: 1,
label: '节点1',
children: [
{
id: 2,
label: '子节点1'
}
]
}
]
扁平化数据结构转换方法

function flattenTree(nodes, level = 0) {
return nodes.reduce((acc, node) => {
return [
...acc,
{ ...node, level },
...(node.children ? flattenTree(node.children, level + 1) : [])
]
}, [])
}






