# 递归组件
组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事。
注意
请确保递归调用是条件性的 (例如使用一个最终会得到 false 的 v-if),否则会导致“max stack size exceeded”错误(无限循环)
# 一、数据
# 1、扁平数据
方便后端将数据存储到数据库中
let data = [
{
id: '51', // 区域 id
name: '四川省', // 区域名字
pid: '0' // 区域的父级区域 id
},
{
id: '5101',
name: '成都市',
pid: '51' // 成都的父级是四川省,所以 pid 是 51
}
// ...
]
# 2、树形数据
方便前端将数据展示到页面
let treeData = [
{
id: '51', // 地址 id
name: '四川省', // 地址名
pid: '0', // 该地址的父节点 id
children: [
{
id: '5101',
name: '成都市',
pid: '51',
children: [
{
id: '510101',
name: '市辖区',
pid: '5101',
children: [] // 如果该区域节点没有子集,children 则为空数组!!!
}
// ...
]
}
// ...
]
}
// ...
]
# 二、开发应用
# 1、数据转换
function convertToTree(regions, rootId = '0') {
// 方式1:使用forEach
let childList = []
regions.forEach((item) => {
if (item.pid === rootId) {
// 1、获取孩子节点A
childList.push(item)
// 2、将与A匹配的孩子节点添加到 item.children 上
item.children = convertToTree(regions, item.id)
}
})
return childList
// // 方式2:使用filter
// // 1、获取孩子节点A
// let childList = regions.filter(item => item.pid === rootId)
// // 2、将与A匹配的孩子节点添加到 item.children 上
// childList.map(item => {
// return item.children = convertToTree(regions, item.id)
// })
// return childList
}
module.exports = convertToTree // 检测需要,请勿删除
# 2、递归组件
当然类似的还有:
- 导航菜单 —— vue-element-admin (opens new window)
- 组织架构图
- 评论系统
下面以评论系统为例,写一个简单的案例:
树形结构数据
const comments = [
{
id: 1,
text: 'First comment',
replies: [
{
id: 2,
text: 'Reply 1',
replies: []
},
{
id: 3,
text: 'Reply 2',
replies: [
{
id: 4,
text: 'Nested reply',
replies: []
}
]
}
]
},
{
id: 5,
text: 'Second comment',
replies: []
}
]
<template>
<div>
<Comment v-for="comment in comments" :key="comment.id" :comment="comment" />
</div>
</template>
<script>
import Comment from './Comment.vue'
export default {
name: 'App',
components: {
Comment
},
data() {
return {
comments: [
// 数据结构
]
}
}
}
</script>
<!-- Comment.vue -->
<template>
<div class="comment">
<div class="comment-content">{{ comment.text }}</div>
<div v-if="comment.replies && comment.replies.length > 0" class="comment-replies">
<Comment v-for="reply in comment.replies" :key="reply.id" :comment="reply" />
</div>
</div>
</template>
<script>
export default {
name: 'Comment',
props: {
comment: {
type: Object,
required: true
}
}
}
</script>