vue递归实现
Vue 递归实现方法
在 Vue 中实现递归组件通常用于树形结构、嵌套菜单等场景。以下是几种常见的实现方式:

使用组件自身递归
通过组件调用自身实现递归,注意必须设置 name 属性以便组件内部引用:

<template>
<div>
<div>{{ node.label }}</div>
<tree-node
v-for="child in node.children"
:key="child.id"
:node="child"
/>
</div>
</template>
<script>
export default {
name: 'TreeNode', // 必须设置name
props: {
node: Object
}
}
</script>
动态组件递归
通过 :is 动态绑定组件实现递归:
<template>
<div>
<component
:is="componentName"
v-for="item in items"
:key="item.id"
:item="item"
/>
</div>
</template>
<script>
export default {
name: 'RecursiveComponent',
props: {
item: Object
},
computed: {
componentName() {
return this.item.children ? 'RecursiveComponent' : 'LeafComponent'
}
}
}
</script>
递归渲染数组
处理嵌套数组数据时,可以使用计算属性或方法递归处理:
<template>
<ul>
<li v-for="item in flattenItems" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>
<script>
export default {
props: {
items: Array
},
computed: {
flattenItems() {
return this.flatten(this.items)
}
},
methods: {
flatten(arr) {
return arr.reduce((acc, item) => {
acc.push(item)
if (item.children) {
acc.push(...this.flatten(item.children))
}
return acc
}, [])
}
}
}
</script>
递归组件的注意事项
- 必须设置终止条件,防止无限递归导致栈溢出
- 对于深层递归,考虑使用虚拟滚动优化性能
- 复杂场景可以结合 Vuex 或 Provide/Inject 管理状态
- 递归组件可能导致渲染性能问题,建议限制递归深度
递归组件的实际应用示例
文件目录树实现
<template>
<div class="folder">
<div @click="toggle">
{{ folder.name }} {{ isOpen ? '-' : '+' }}
</div>
<div v-show="isOpen" class="contents">
<tree-folder
v-for="child in folder.children"
:key="child.name"
:folder="child"
/>
</div>
</div>
</template>
<script>
export default {
name: 'TreeFolder',
props: {
folder: Object
},
data() {
return {
isOpen: false
}
},
methods: {
toggle() {
this.isOpen = !this.isOpen
}
}
}
</script>
无限级评论回复
<template>
<div class="comment">
<div>{{ comment.text }}</div>
<button @click="showReplies = !showReplies">
{{ showReplies ? '隐藏' : '显示' }}回复
</button>
<div v-if="showReplies" class="replies">
<comment
v-for="reply in comment.replies"
:key="reply.id"
:comment="reply"
/>
</div>
</div>
</template>
<script>
export default {
name: 'Comment',
props: {
comment: Object
},
data() {
return {
showReplies: false
}
}
}
</script>






