组件自动引入并全局注册场景
在一个大型项目的开发中,我们一定会有很多全局公用的公共组件,并且随着项目的深入,组件会越来越多。
比如,我们在src\components\common文件夹用于存放公共组件,这些组件是需要全局注册使用的。
一开始,我们可能只有 Bread.vue(面包屑)组件和bannner(轮播图)组件
我们需要全局注册使用
// component/index.js
import {
Bread,banner} from '../components/common'
export default (Vue) => {
Vue.component('Bread', Bread)
Vue.component('banner', banner)
}
然后,在main.js中使用
// 导入一个函数
import component from './components/index.js'
// 使用该函数,使里面全局挂载的组件生效
Vue.use(component)
组件很少的时候,一个个全局注册也不麻烦,但是,如果我们组件越来越多,我们每写一个组件,就要额外引入注册一次,非常麻烦!
// component/index.js
import {
Bread,banner,Title,Card,Pic,Popver,Hover,Test} from '../components/common'
export default (Vue) => {
Vue.component('Bread', Bread)
Vue.component('banner', banner)
Vue.component('Title',Title)
Vue.component('Card', Card)
Vue.component('Pic', Pic)
Vue.component('Popver', Popver)
Vue.component('Hover', Hover)
// ....
}
这样写太愚蠢了!有什么办法自动引入并注册吗?当然有!
vue-cli脚手架下的组件自动引入注册
vue-cli底层是基于webapck的,因此,我们实际上是借助webapck实现组件的全局注册引入的!
代码实现
假设我们的components/common下有非常多的组价,借助webapck实现这个功能,我们只需要这么写
// component/index.js
// 使用webpack语法自动导入全部自定义的公共组件
const comments = require.context('../components/common', true, /.(vue)$/)
export default (Vue: any) => {
//自动化全局注册自定义的公共组件
comments.keys().forEach((fileName: any) => {
Vue.component(fileName.match(/^.\/(.*).vue$/)[1], comments(fileName).default)
})
}
是不是非常简单!那么这个require.context是干什么的?
require.context
require.context是webpack自动化导入多个模块的一个工具。
基础用法
require.context(directory, useSubdirectories, regExp)
属性名 | 含义 |
---|---|
directory | 要查找的文件路径 |
useSubdirectories | 是否查找子目录 |
regExp | 要匹配文件的正则 |
const comments = require.context('../components/common', true, /.(vue)$/)
这句代码的意思就是从../components/common文件夹进行子集目录遍历,查找所有的.vue结尾的文件。
comments返回的是一个函数,comments.keys()返回的是一个包含文件名的数组,本示例中返回的数组是
consol.log(comments.keys()) // [Bread.vue,banner.vue,...]
comments.keys().forEach((fileName: any) => {
console.log(comments)
Vue.component(fileName.match(/^.\/(.*).vue$/)[1], comments(fileName).default)
})
这句代码也很好理解,遍历comments.keys()这个数组,使用 Vue.component()方法全局注册所有的组件。
每个 Vue.component()方法内,用数组中每一个文件的名字作为组件名(去掉.vue后缀),然后传入组件的配置对象。
comments(fileName).default返回的是每一个组件的配置对象
其他写法
import Vue from 'vue';
// 使用require.context自动引入所有的组件
const requireComponent = require.context(
// 组件目录的相对路径
'./components',
// 是否查询子目录
false,
// 匹配基础组件文件名的正则表达式
/[A-Z]\w+\.(vue|js)$/
);
requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName);
// 获取组件的 PascalCase 命名
const componentName = fileName
.split('/')
.pop()
.replace(/\.\w+$/, '');
// 全局注册组件
Vue.component(
componentName,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`,
// 否则回退到使用模块的根。
componentConfig.default || componentConfig
);
});
vite中组件的自动引入与注册
在使用 Vite 构建 Vue 项目时,我们可以通过 import.meta.glob 方法来批量引入和注册组件。import.meta.glob 是 Vite 提供的一个功能,类似于 Webpack 的 require.context。
代码实现
创建自动引入和全局注册脚本
在 src 目录下创建一个文件,例如 globalComponents.js,用于自动引入和全局注册组件:
src/globalComponents.js:
import {
defineAsyncComponent } from 'vue';
export default function registerGlobalComponents(app) {
const components = import.meta.glob('./components/*.vue');
for (const path in components) {
const componentName = path.split('/').pop().replace(/\.\w+$/, '');
app.component(componentName, defineAsyncComponent(components[path]));
}
}
在 main.js 中引入并使用
在 src/main.js 中引入并使用这个自动注册脚本:
src/main.js:
import { createApp } from 'vue';
import App from './App.vue';
import registerGlobalComponents from './globalComponents';
const app = createApp(App);
registerGlobalComponents(app);
app.mount('#app');
import.meta.glob
import.meta.glob 参数
- pattern:字符串或字符串数组,表示匹配文件的路径模式。可以使用通配符 *。
options:一个对象,可以包含以下属性:
- eager:布尔值,如果为 true,将立即加载模块,而不是返回一个导入函数。
- import:函数,用于自定义导入。
- expose:数组,指定哪些命名导出应该被暴露。
ignore:字符串或字符串数组,表示要忽略的文件模式。
const components = import.meta.glob('./components/*.vue', { eager: true }); console.log(components); /* 输出类似于: { './components/Bread.vue': Module, './components/Banner.vue': Module } */
总结
在大型的前端项目中,手动引入和全局注册公共组件既繁琐又易出错。我们可以通过Webpack的require.context或Vite的import.meta.glob,可以自动引入并全局注册组件。require.context适用于基于Webpack的项目,而import.meta.glob适用于Vite构建的项目,这两种方法都大大简化了组件管理,提高了开发效率。