vue 递归实现树
递归组件实现树形结构
在Vue中可以通过递归组件实现树形结构的渲染,核心思路是组件内部调用自身。以下是一个完整的实现示例:
<template>
<div class="tree">
<tree-node :node="treeData" @on-select="handleSelect"></tree-node>
</div>
</template>
<script>
import TreeNode from './TreeNode.vue'
export default {
components: { TreeNode },
data() {
return {
treeData: {
id: 1,
label: 'Root',
children: [
{
id: 2,
label: 'Child 1',
children: [
{ id: 3, label: 'Grandchild 1' },
{ id: 4, label: 'Grandchild 2' }
]
},
{ id: 5, label: 'Child 2' }
]
}
}
},
methods: {
handleSelect(node) {
console.log('Selected node:', node)
}
}
}
</script>
TreeNode组件实现
<template>
<div class="node">
<div @click="toggle" :class="{ 'has-children': hasChildren }">
{{ node.label }}
</div>
<div v-show="isOpen" v-if="hasChildren" class="children">
<tree-node
v-for="child in node.children"
:key="child.id"
:node="child"
@on-select="$emit('on-select', $event)"
></tree-node>
</div>
</div>
</template>
<script>
export default {
name: 'TreeNode',
props: {
node: {
type: Object,
required: true
}
},
data() {
return {
isOpen: false
}
},
computed: {
hasChildren() {
return this.node.children && this.node.children.length
}
},
methods: {
toggle() {
if (this.hasChildren) {
this.isOpen = !this.isOpen
}
this.$emit('on-select', this.node)
}
}
}
</script>
<style>
.node {
margin-left: 20px;
cursor: pointer;
}
.has-children {
font-weight: bold;
}
.children {
margin-left: 15px;
}
</style>
关键实现要点
递归组件的核心是在组件内部通过name属性注册自身,然后在模板中直接使用。必须设置name属性才能实现递归调用。
数据结构通常采用嵌套的children形式,每个节点包含:
- id: 唯一标识
- label: 显示文本
- children: 子节点数组(可选)
通过v-show控制子节点的展开/折叠状态,计算属性hasChildren判断当前节点是否有子节点。
性能优化建议
对于大型树结构,可以采用虚拟滚动优化:
- 计算可见区域内的节点
- 只渲染可见部分节点
- 滚动时动态更新渲染节点
// 虚拟滚动示例
const visibleNodes = computed(() => {
return allNodes.value.slice(
startIndex.value,
Math.min(startIndex.value + visibleCount.value, allNodes.value.length)
)
})
动态加载实现
当树节点数据量很大时,可以按需加载子节点:
methods: {
async loadChildren(node) {
if (!node.childrenLoaded && !node.children) {
const res = await api.getChildren(node.id)
this.$set(node, 'children', res.data)
this.$set(node, 'childrenLoaded', true)
}
this.isOpen = !this.isOpen
}
}
注意事项
递归组件需要合理控制递归深度,过深的嵌套可能导致堆栈溢出。建议对树形数据做扁平化处理时设置最大深度限制。
组件样式需要注意层级缩进,通过margin-left实现视觉上的树形层次感。交互方面建议添加展开/折叠动画提升用户体验。







