起因
之前在我们项目的main.ts中看到了一行这样的代码
ts
app.component('svg-icon', SvgIcon)
每每看到他我心里就很痒,思考为什么要把他扔到mian.ts里面。
问题分析
终于在业务不忙的是我决定把它解决掉,我准备参考一下element-puls的方案看看他是如何处理icon并且全局注册的.
看完之后,我准备写一个插件来处理他,让他支持异步的导入全局组件,不说了直接开动。
书写vue插件
我们先来定义一个数据类型用一个数组来存放所有的异步组件,数组元素的类型是对象里面有两个属性是key和component,直接开干
ts
//插件部分
import type { App, Component } from 'vue'
type options = {
key: string
component: Component
}[]
export default {
install: (app: App<Element>, options: Readonly<options>) => {
options.forEach((item) => {
app.component(item.key, item.component)
})
}
}
//数组定义
export const globalComponents = [
{
key: 'svg-icon',
component: () => import('@/components/SvgIcon/index.vue')
},
{
key: 'Modal',
component: () => import('@/components/Modal/index.vue')
}
] as const
//main函数调用
import asyncRegisterGlobalComponents from '../plugins/asyncRegisterGlobalComponents'
app.use(asyncRegisterGlobalComponents, globalComponents)
这里书写了一个简单的插件,他的目的就是通过app.component
去注册globalComponents
中定义的组件,通过() => import('@/components/Modal/index.vue')
来让组件实现异步注册。
处理全局组件的类型问题
我们如果在全局注册组件之后,需要把类型定义到global.d.ts
中。
ts
// global.d.ts
import SvgIcon form '@/components/SvgIcon/index.vue'
declare module 'vue' {
export interface GlobalComponents {
SvgIcon:typeof SvgIcon
}
}
但是在这里我们完全没有必要这么去处理这个类型,我们完全可以通过体操来根据数组自动去生成他的类型。
ts
import { ExtendedObjectType } from '@/interface/utilsType'
import { globalComponents } from '@/utils/globalComponents'
type TGlobalComponents<
T extends typeof globalComponents = typeof globalComponents,
num extends number[] = [],
globalObj extends Partial<Record<keyof T[number]['key'], keyof T[number]['component']>> = {}
> = num['length'] extends T['length']
? globalObj
: TGlobalComponents<
T,
[...num, 0],
ExtendedObjectType<
globalObj,
Record<
T[num['length']]['key'],
Awaited<ReturnType<T[num['length']]['component']>>['default']
>
>
>
declare module 'vue' {
export interface GlobalComponents extends TGlobalComponents {}
}
这里用到了一个之前写的工具类型ExtendedObjectType
,他主要是处理将两个对象联合起来.
ts
type _BaseObjType = { [k in PropertyKey]: unknown }
// 用于对象类型合并
export type ExtendedObjectType<obj1 extends _BaseObjType, obj2 extends _BaseObjType> = {
[k in keyof obj1 | keyof obj2]: k extends Extract<keyof obj1, keyof obj2>
? obj1[k] | obj2[k]
: k extends keyof obj1
? obj1[k]
: obj2[k]
}
结果
废话不多说了直接看看效果,这里没有导入这个组件,他自动识别到了这个组件并且给了类型提示。