- 该文章是在学习 小满vue3 课程的随堂记录
- 示例均采用
<script setup>
,且包含typescript
的基础用法
一、使用场景
递归组件
的使用场景,如 无限级的菜单
,接下来就用菜单的例子来学习
二、具体使用
先把菜单的基础内容写出来再说
父组件
html
<Tree :data="mock" />
ts
// 引入子组件
import Tree from "../components/17_组件/Tree.vue";
// 菜单的数据格式
interface ITree {
name: string;
checked: boolean;
children?: ITree[];
}
// 数据 mock
const mock: ITree[] = [
{
name: "1",
checked: false,
children: [
{
name: "1-1",
checked: true,
},
],
},
{
name: "2",
checked: false,
},
{
name: "3",
checked: false,
children: [
{
name: "3-1",
checked: false,
children: [
{
name: "3-1-1",
checked: true,
},
],
},
],
},
];
子组件
html
<!-- 第一层数据 -->
<div v-for="item in data" style="margin-left: 16px">
<input type="checkbox" v-model="item.checked" />
{{ item.name }}
</div>
ts
<script setup lang="ts">
// 这里为了方便直接拷贝过来了,实际项目中要抽离出来复用
interface ITree {
name: string;
checked: boolean;
children?: ITree[];
}
// props 定义
defineProps<{
data?: ITree[];
}>();
</script>
如图,上述代码已经完成了 第一层
菜单数据的渲染:
深层
的菜单数据,就要用到 递归组件
了,递归组件有以下 三种
使用方式
1、直接使用 自己的文件名
作为 组件名称
,不需要引入
当前的文件名称是 Tree.vue
,所以直接使用 Tree
即可
子组件
html
<!-- 第一层数据 -->
<div v-for="item in data" style="margin-left: 16px">
<input type="checkbox" v-model="item.checked" />
{{ item.name }}
<!-- 需要注意:需要按照格式传入子组件要用的数据,并且加上递归的判断条件 -->
<Tree v-if="item?.children?.length" :data="item.children"></Tree>
</div>
使用结果如下:
2、子组件中再定义一个 script,并暴露出 name
子组件
ts
<script lang="ts">
// 再起一个 script(lang必须保持一致),用来定义该组件的 name
export default {
name: "TreeVue",
};
</script>
使用时,就可以用自定义的组件名
html
<!-- 第一层数据 -->
<div v-for="item in data" style="margin-left: 16px">
<input type="checkbox" v-model="item.checked" />
{{ item.name }}
<!-- 深层数据 -->
<TreeVue v-if="item?.children?.length" :data="item.children"></TreeVue>
</div>
渲染结果一致:
3、使用 defineOptions 自定义组件名
Vue3.3
增加了defineOptions
方法,用来定义optionsAPI
中的选项,比如组件名称 name(老一点的 vue 版本要装插件才能使用 defineOptions)- 与上面第二种思路一致,就是起个名再用
子组件
ts
<script setup lang="ts">
interface ITree {
name: string;
checked: boolean;
children?: ITree[];
}
defineProps<{
data?: ITree[];
}>();
// 直接在原有的 script 中进行自定义
defineOptions({
name: "Self",
});
</script>
html
<!-- 第一层数据 -->
<div v-for="item in data" style="margin-left: 16px">
<input type="checkbox" v-model="item.checked" />
{{ item.name }}
<!-- 深层数据 -->
<Self v-if="item?.children?.length" :data="item.children"></Self>
</div>
渲染结果仍然一致,不再赘述