没啥讲的,和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组件本身)

    <template>
            左侧导航菜单
            <Tree @on-click="getItem" :data="data"></Tree>
    </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>
    </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>