【Vue3.x】全局组件、局部组件和递归组件
全局组件
没啥讲的,和vue2一样,常规是src下components文件夹下新建全局组件,然后去入口文件main.ts里注册全局组件。然后就能在全局使用了
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
const app = createApp(App)
// 引入全局组件(GlobalComponent为具体组件名,请替换)
import GlobalComponent from "./components/GlobalComponent"
// 注册全局组件(component 第一个参数组件名称 第二个参数组件实例)
app.component("GlobalComponent",GlobalComponent);
app.use(store).use(router).mount('#app')
局部组件
就是最常规的手动引入路径后,在使用局部组件。每在一个不同的组件想使用,都必须手动引入。
递归组件
递归树结构组件,并设置递归边界,否则会引起内存泄漏。
递归组件的使用场景
- 任何存在树组件的地方:展示文件的层级
- 左侧导航栏:根据路由层级生成的导航菜单(导航是由后端传来的)
- 多级表格(嵌套的表格)
以下是一个左侧动态导航的菜单案例,Menu为祖先组件,Tree为树结构子组件,TreeItem为递归Tree组件时别名(就是Tree组件本身)
Menu祖先组件
<template>
<div>
左侧导航菜单
<Tree @on-click="getItem" :data="data"></Tree>
</div>
</template>
<script setup lang='ts'>
import Tree from "../../components/Tree/index.vue";
import { reactive } from 'vue';
// 通过接口约束树结构
interface TreeList {
name: string,
icon?: string,
children?: TreeList[] | [] // 子集为联合类型,可能是同样的树结构,也可能是空数组。甚至children是可选的。
}
// 递归的数据结构,我们并不知道他具体的层级,并通过props传给子组件Tree
const data = reactive<TreeList[]>([
{
name: 'no.1',
children: [
{
name: "no.1-1",
children: [
{ name: 'no.1-1-1' }
]
}
]
},
{
name: 'no.2',
children: [
{
name: 'no.2-1'
}
]
},
{
name: 'no.3'
},
{
name: 'no.4',
children: []
}
])
const getItem = (item: TreeList) => {
console.log(item, '父组件拿取到了item');
}
</script>
Tree树结构子组件
<template>
<!-- 给一个margin区分层级 -->
<div style="margin-left:10px">
<!--
这里绑定的两个clickItem需要理解一下,比较绕
父级div定义了clickItem事件,但是不允许冒泡,因为我们想知道点击的子级的具体哪一个,如果不加stop将无法区分子级
由于父级div取消了clickItem事件冒泡,子级TreeChild必须另外绑定监听事件
-->
<div @click.stop="clickItem(item)" v-for="(item,index) in data" :key="index">
{{item.name}}
<TreeChild @on-click="clickItem" :data="item.children" v-if="item?.children?.length"></TreeChild>
</div>
</div>
</template>
<script setup lang='ts'>
// 递归引入自身并取
import TreeChild from "./index.vue";
// 通过接口约束树结构(并递归子集),递归边界是子集没有children了
interface TreeList {
name: string,
icon?: string,
children?: TreeList[] | [] // 子集为联合类型,可能是同样的树结构,也可能是空数组。甚至children是可选的,没有children就是递归边界
}
// 通过接口并使用泛型约束-父组件传来的props data树形结构
interface Props<T> {
data?: T[] | []
};
// 接受父组件传来的props data树形结构,并使用泛型约束props
defineProps<Props<TreeList>>()
// 子→父通信,告知父组件Menu当前点击的是具体哪一个菜单
const emit = defineEmits(['on-click'])
const clickItem = (item: TreeList) => {
emit('on-click', item)
}
</script>
洗尽铅华始见金,褪去浮华归本真