【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')

局部组件

就是最常规的手动引入路径后,在使用局部组件。每在一个不同的组件想使用,都必须手动引入。

递归组件

递归树结构组件,并设置递归边界,否则会引起内存泄漏。

递归组件的使用场景

  1. 任何存在树组件的地方:展示文件的层级
  2. 左侧导航栏:根据路由层级生成的导航菜单(导航是由后端传来的)
  3. 多级表格(嵌套的表格)

以下是一个左侧动态导航的菜单案例,Menu为祖先组件,Tree为树结构子组件,TreeItem为递归Tree组件时别名(就是Tree组件本身)

<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>
posted @ 2022-10-06 00:24  wanglei1900  阅读(298)  评论(0编辑  收藏  举报