第一种方式,直接自己调用自己
Tree.vue
<template><div class="tree"><div v-for="(item, index) in data" :key="item.name">每一层 {{ item.name }}<Tree v-if="item?.children?.length" :data='item.children' /></div></div>
</template><script setup lang="ts">
//递归的第一种方式 直接引入自己
import Tree from './Tree.vue'
import { TreeList } from '../ts/type'
type Props = {data?: TreeList[]
}
defineProps<Props>();
</script><style scoped>
.tree {margin-left: 20px;border-left: 2px #01847f dashed;
}
</style>
App.vue 里模拟树形数据,使用递归组件
<template><div><Tree :data='data'/></div>
</template><script setup lang="ts">
import Tree from './components/Tree.vue'
import { reactive } from 'vue'
import {TreeList } from './ts/type'
const data = reactive<TreeList[]>([{name: 'no.1',children: [{name: 'no.1-1',children: [{name: 'no.1-1-1',children:[]}]},],}, {name:'no.2'}, {name: 'no.3',children: [{name:'no.3-1'}]}])
</script><style scoped></style>
type.ts 属性数据的结构
export type TreeList = {name: string //名称icon?: string //图标可有可无children?: TreeList[] | [] //子节点 可有可无 还可能传空数组
}
第二种方式,export 一个name出去
第二种方式 就是像vue2 一样 export一个name出去
但是setup 语法糖下没办法使用 export
我们只需要再定义一个script标签就可以了
<template><div class="tree"><div v-for="(item, index) in data" :key="item.name">每一层 {{ item.name }}<Tree v-if="item?.children?.length" :data='item.children' /></div></div>
</template><script setup lang="ts">
import { TreeList } from '../ts/type'
type Props = {data?: TreeList[]
}
defineProps<Props>();
</script>
<!-- 第二种方式 就是像vue2 一样 export一个name出去但是setup 语法糖下没办法使用 export 我们只需要再定义一个script标签就可以了-->
<script lang="ts">
export default {name:'Tree'
}
</script><style scoped>
.tree {margin-left: 20px;border-left: 2px #01847f dashed;
}
</style>
效果图
我们还可以给树形递归的组件添加参数传递事件
要注意在树形组件的里层也得添加自定义事件
并且这个自定义事件传的函数很有讲究
Tree.vue
<template><div class="tree"><div @click.stop="clickTreeItem(item)" v-for="(item, index) in data" :key="item.name">每一层 {{ item.name }}<Tree @get-tree-item="clickTreeItem" v-if="item?.children?.length" :data='item.children' /><!-- Tree 组件不添加这个自定义事件的话 那么就只有最外层的根节点会向外传递数据 --><!-- 注意此处派发的函数clickTreeItem没有传item参数了如果传了就相当于给树形组件(递归组件)的上级派发信息 没办法从外部拿到子节点所传递的数据了 --><!-- @get-tree-item="clickTreeItem(item)" 写成这种形式的话 递归组件会依次向上层传递事件 --><!-- 不传item的执行结果如下 --><!--子组件派发的item Proxy {name: 'no.1-1-1', children: Array(0)}子组件派发的item Proxy {name: 'no.1-1-1', children: Array(0)}子组件派发的item Proxy {name: 'no.1-1-1', children: Array(0)}父组件得到的item Proxy {name: 'no.1-1-1', children: Array(0)} --><!-- 传item的执行的结果如下 --><!-- 子组件派发的item Proxy {name: 'no.1-1-1', children: Array(0)}子组件派发的item Proxy {name: 'no.1-1', children: Array(1)}子组件派发的item Proxy {name: 'no.1', children: Array(1)}父组件得到的item Proxy {name: 'no.1', children: Array(1)} --></div></div>
</template><script setup lang="ts">
import { TreeList } from '../ts/type'
type Props = {data?: TreeList[]
}
defineProps<Props>();const emit = defineEmits(['getTreeItem'])
const clickTreeItem=(item:TreeList)=>{console.log('子组件派发的item', item)emit('getTreeItem',item)
}
</script>
<!-- 第二种方式 就是像vue2 一样 export一个name出去但是setup 语法糖下没办法使用 export 我们只需要再定义一个script标签就可以了-->
<script lang="ts">
export default {name:'Tree'
}
</script><style scoped>
.tree {margin-left: 20px;border-left: 2px #01847f dashed;
}
</style>
App.vue
<template><div><Tree :data='data' @get-tree-item="getTreeItem"/></div>
</template><script setup lang="ts">
import Tree from './components/Tree.vue'
import { reactive } from 'vue'
import {TreeList } from './ts/type'
const data = reactive<TreeList[]>([{name: 'no.1',children: [{name: 'no.1-1',children: [{name: 'no.1-1-1',children:[]}]},],}, {name:'no.2'}, {name: 'no.3',children: [{name:'no.3-1'}]}])const getTreeItem = (item:TreeList) => {console.log('父组件得到的item',item)
}
</script><style scoped></style>