递归组件
什么是递归组件
递归组件,顾名思义,就是自己的内部实现又调用自己的组件。 特点:
- 组件必须设置 name 选项
递归组件的实现
Vue 官方实例 Tree-View
-
Home.vue
:::details 点击查看代码
<template>
<div class="home">
<Tree></Tree>
</div>
</template>
<script>
import Tree from "./Tree";
export default {
name: "Home",
components: {
Tree,
},
};
</script>:::
-
Tree.vue
:::details 点击查看代码
<template>
<ul class="Tree">
<TreeItem
class="TreeItem"
:item="treeData"
@make-folder="makeFolder"
@add-item="addItem"
></TreeItem>
</ul>
</template>
<script>
import TreeItem from "./TreeItem";
export default {
name: "Tree",
components: {
TreeItem,
},
data() {
return {
treeData: {
name: "世界您好!",
children: [
{
name: "美国不好!",
},
{
name: "英国不好!",
},
{
name: "中国您好!",
children: [
{
name: "北京好!",
},
{
name: "杭州好!",
},
{
name: "太原好!",
},
],
},
],
},
};
},
methods: {
makeFolder(item) {
this.$set(item, "children", []);
this.addItem(item);
},
addItem(item) {
console.log(item);
if (!item.children) {
this.$set(item, "children", []);
}
item.children.push({
name: "新世界",
});
},
},
};
</script>
<style>
.Tree {
padding-left: 1em;
line-height: 1.5em;
list-style-type: dot;
}
.TreeItem {
cursor: pointer;
}
.folder {
font-weight: bold;
}
</style>:::
-
TreeItem.vue
:::details 点击查看代码
<template>
<li>
<div :class="{ folder: isFolder }" @click="toggle" @dblclick="makeFolder">
{{ item.name }}
<span v-if="isFolder">[{{ isOpen ? "-" : "+" }}]</span>
</div>
<ul v-show='isOpen' v-if='isFolder' class="Tree">
<TreeItem
class="TreeItem"
v-for="(child, index) in item.children"
:key="index"
:item="child"
@make-folder="$emit('make-folder', $event)"
@add-item="$emit('add-item', $event)"
></TreeItem>
<li class="add" @click="$emit('add-item', item)">+</li>
</ul>
</li>
</template>
<script>
export default {
name: "TreeItem",
components: {},
props: {
item: {
type: Object,
},
},
data() {
return {
isOpen: false,
};
},
computed: {
isFolder() {
return this.item.children && this.item.children.length;
},
},
methods: {
toggle() {
if (this.isFolder) {
this.isOpen = !this.isOpen;
}
},
makeFolder() {
if (!this.isFolder) {
this.$emit("make-folder", this.item);
this.isOpen = true;
}
},
},
};
</script>:::