在Vue项目开发中,经常需要import或者export各种模块,当一个页面中组件很多时,我们可能会这样引入组件:
import A from 'components/A.vue'
import B from 'components/B.vue'
import C from 'components/C.vue'
import D from 'components/D.vue'
要是每加一个组件,都要写这么一句 import ,那岂不是很蛋疼,是否可以通过自动化引入呢?
答案是肯定有的,那就要使用 webpack 给我们提供的 require.context
API:
require.context(directory, useSubdirectories, regExp)
它接收三个参数:
- directory: 要查找的文件路径
- useSubdirectories: 是否查找子目录
- regExp: 要匹配文件的正则
比如我在根目录 src/components
文件夹下有 A.vue
、B.vue
、C.vue
、D.vue
四个组件文件,那我就可以通过它获取所需要的信息:
const ctx = require.context('./src/components', false, /\.vue$/)
我们可以打印一下 ctx
,看返回的是什么内容:
var map = {
"./A.vue": "./src/components/A.vue",
"./B.vue": "./src/components/B.vue",
"./C.vue": "./src/components/C.vue",
"./D.vue": "./src/components/D.vue"
};
function webpackContext(req) {
var id = webpackContextResolve(req);
return __webpack_require__(id);
}
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return id;
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = "./src/components sync recursive \\.vue$";
从打印结果可以看出,require.context执行后,返回一个方法 webpackContext,这个方法又返回一个__webpack_require__,__webpack_require__就相当于require或者import。
同时 webpackContext 还有两个静态方法 keys 与 resolve,一个 id 属性。
- keys:返回匹配成功模块的名字组成的数组;
- resolve:接受一个参数request,request为
./src/components
文件夹下面匹配文件的相对路径,返回这个匹配文件相对于整个工程的相对路径; - id:执行环境的id,返回的是一个字符串,主要用在module.hot.accept,应该是热加载看下keys是作用。
这样一来,通过 ctx.keys()
我们可以得到匹配文件的相对路径数组:
["./A.vue", "./B.vue", "./C.vue", "./D.vue"]
基于以上数组,我们就可以封装一个自动引入组件的方法了,比如在 utils
文件夹下创建 componentsRegister.js
文件:
// 处理首字母大写 abc => Abc
function changeStr(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 自动注册组件
*/
export default {
install (Vue) {
const requireComponent = require.context('./src/components/', false, /[A-Z]\w+\.(vue|js)$/)
requireComponent.keys().forEach(fileName => {
const config = requireComponent(fileName);
const componentName = changeStr(
fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
);
Vue.component(componentName, config.default || config); // 动态注册该目录下的所有.vue文件
})
}
}
最后在入口文件 main.js
中导入封装好的文件,即可实现组件的自动化引入:
import Vue from 'vue'; // 引入vue
import componentsList from './utils/componentsRegister';
Vue.use(componentsList);