vite+vue3项目批量注册自定义组件的方法

6,259 阅读1分钟

vue2中全局注册自定义组件的方法一般都是使用webpack提供的require.context,那么vue3中如何全局批量注册自定义组件呢?通过阅读本文一起揭晓答案吧~

先直接上结论,代码如下:

import { App, defineAsyncComponent } from 'vue'
export default {
  install(app: App, obtions: any) {
    const requireModules = import.meta.glob('../components/common/*.vue')
    for (const path in requireModules) {
      const result: Array<any> = path.match(/.*/(.+).vue$/)!
      const modulesConent: any = requireModules[path]
      app.component(result[1], defineAsyncComponent(modulesConent))
    }
  }
}

喜欢看过程的可以继续看,不喜欢看的直接拿走这段代码改改全局组件路径就能用到您的项目中。

1.逐个手动注册

import Search from './components/common/Search.vue'
import TableHeader from './components/common/TableHeader.vue'

app.component('Search', Search).component('TableHeader', TableHeader)

组个引入的优点是简单,对开发者来说基本没啥心智负担;缺点是增加一个全局组件则需要注册一次,在需要全局注册的自定义组件非常多的情况下显然不是明智之举。

2.import.meta.globEager

查了一下资料,有的文章说可以使用import.meta.globEager来全局引入组件,代码如下

type Module = { [key: string]: any }
const COMS: Record<string, Module> = import.meta.globEager(
  './components/common/*.vue'
)
Object.keys(COMS).forEach((key) => {
  //匹配.vue结尾的文件名
  const match: RegExpMatchArray | null = key.match(/[\w]+(?=.vue)/)
  if (!match) return
  //组件名
  const name: string = match[0]
  //组件实例
  const component: Module = COMS[key].default
  //全局注册
  app.component(name, component)
})

使用import.meta.globEager读取components/common路径下的vue文件然后逐一注册,非常方便。但是编辑器提示globEager已经弃用,vite官方文档也说明使用import.meta.glob来代替import.meta.globEager。

3.import.meta.glob

3.1 初步尝试

仿照 import.meta.globEager的解决办法写了如下代码:

const requireModules = import.meta.glob('./components/common/*.vue')
for (const path in requireModules) {
  const componentName = path.substring(
    path.lastIndexOf('/') + 1,
    path.lastIndexOf('.')
  )
  const modulesConent: any = requireModules[path]
  modulesConent().then((res: any) => {
    app.component(componentName, res.deafult)
  })
}

但是这样并不能起作用,需要vue3提供的defineAsyncComponent,此方法用于定义一个异步组件,它在运行时是懒加载的。参数可以是一个异步加载函数,或是对加载行为进行更具体定制的一个选项对象。

修改后的代码如下所示:

const requireModules = import.meta.glob('./components/common/*.vue')
for (const path in requireModules) {
  const componentName = path.substring(
    path.lastIndexOf('/') + 1,
    path.lastIndexOf('.')
  )
  const modulesConent: any = requireModules[path]
  app.component(componentName, defineAsyncComponent(modulesConent))
}

3.2 优化:使用正则表达式提取组件名

使用正则表达式优化组件名获取的逻辑:

// 全局注册组件
const requireModules = import.meta.glob('./components/common/*.vue')
for (const path in requireModules) {
  const result: Array<any> = path.match(/.*/(.+).vue$/)!
  const modulesConent: any = requireModules[path]
  app.component(result[1], defineAsyncComponent(modulesConent))
}

result打印的信息如下:

可以看到result[1]就是组件名。

3.3 自定义插件

我们继续优化代码,将其改为自定义插件。一个vue插件可以是一个拥有 install() 方法的对象,也可以直接是一个安装函数本身,安装函数会接收到安装它的vue应用实例和传递给 app.use() 的额外选项作为参数,如下代码将全局引入组件的方法改为了vue插件的形式:

import { App, defineAsyncComponent } from 'vue'
export default {
  install(app: App, obtions: any) {
    const requireModules = import.meta.glob('../components/common/*.vue')
    for (const path in requireModules) {
      const result: Array<any> = path.match(/.*/(.+).vue$/)!
      const modulesConent: any = requireModules[path]
      app.component(result[1], defineAsyncComponent(modulesConent))
    }
  }
}

obtions是插件可选的参数,调用时的代码:

import ComponentRegister from './plugins/component'
app.use(ComponentRegister, { a: 1 })

如上代码使用了app.use方法安装了插件ComponentRegister,app.use方法可以接收可选的第二个参数,此参数会传给插件的install方法。

参考文章:

VUE3+vite项目中动态引入组件和异步组件

VUE组件的批量全局注册