Vue组件递归

前言

递归函数简单的定义是:一个自调用函数,这意味着它将在执行的某个时刻调用自己

从理论上讲,递归是一种需要两个属性的行为:

  • 结束点:停止递归的情况
  • 一组规则:负责将所有的操作减少到结束点

如果没有结束点,递归将成为一个无限循环,但是如果一组规则就不能实现期望的行为,所以两者都存在才能使它正常工作。

场景

树形结构数据渲染页面

  • 渲染列表数据的时候,列表的子项还是列表,列表的层级多或者层级不确定
  • 在页面上显示文件和子文件但是子文件的数量不确定,同时也不确定子文件中是否还有子文件

举例:组织架构图,文件夹目录,导航菜单,评论列表分级展示

递归组件

在组件中内使用组件本身

代码展示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<template>
<div class="tree-container">
<div class="tree-item" v-for="item in treeData" :key="item.id" @click="itemClick(item)">
<div class="item-title">{{ item.name }}</div>
<Tree v-if="item.children && item.children.length" :treeData="item.children" @itemClick="$emit('itemClick', $event)"></Tree>
</div>
</div>
</template>

<script>
export default {
name: "Tree",
props: {
treeData: {
type: Array,
default: () => []
}
},
methods: {
itemClick(item) {
this.$emit("itemClick", item);
}
}
};
</script>

<style lang="scss" scoped>
.tree-container {
.tree-item {
.tree-item {
margin-left: 20px;
}
.item-title {
padding: 4px 8px;
}

/* 每个层级之间画线 */
&::before {
content: "";
display: block;
position: absolute;
top: 5px;
left: 10px;
height: calc(100% - 50px);
width: 1px;
background-color: #f7f8f9;
}
}
}
</style>

子组件说明

循环体

1
<div class="item-title">{{ item.name }}</div>

循环条件

item.children && item.children.length

获取节点数据

  1. 使用 $emit,将一级节点的 item 传递出去
  2. 将内层节点的数据传递出去,给组件里面的 Tree 绑定 @itemClick="$emit('itemClick', $event)"

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<template>
<Tree :tree-data="treeData"></Tree>
</template>

<script>
const treeData = [
{ id: 1, name: "一级1" },
{
id: 2,
name: "一级2",
children: [
{ id: 3, name: "二级2-1" },
{ id: 4, name: "二级2-2" }
]
},
{
id: 5,
name: "一级3",
children: [
{
id: 6,
name: "二级3-1",
children: [
{ id: 7, name: "三级3-1-1" },
{ id: 8, name: "三级3-1-2" }
]
},
{ id: 9, name: "二级3-2" },
{ id: 10, name: "二级3-3" }
]
}
];
export default {
data() {
return {
treeData
};
}
};
</script>