Vue工程化封装实践系列(三)[组件自动注册]

709 阅读1分钟

本文是:Vue工程化封装实践系列第三篇,相关系列其他文章如下:

  1. axios封装+ vue-bus全局事件通信
  2. vue防止表单重复提交,请求队列取消方法
  3. 组件自动注册+vuex模块自动载入
  4. vuex数据的本地化存储
  5. 路由分模块自动载入
  6. 权限指令封装
  7. 更简洁的代码:render函数
  8. mixin混入
  9. 全局过滤器
  10. directive自定义指令
  11. echarts resize窗口自适应
  12. vue动画高级
  13. less全局变量抽离+自定义多环境打包

组件自动注册

实现思路

目录结构如下:

实现之后就会将当前文件夹下的confirmModal注册为全局组件,在vue文件中使用的时候就不需要再次import 导入了。

代码

componnets/loader.js

// 将components下面的全部vue文件注册为全局组件,组件引用统一按照文件名首字母大写引用

// 将首字母大写 confirmModal 转为  ConfirmModal
function changeStr(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
}

export function ComponentsLoader(Vue) {
    /*    
    webpack的核心Api,建议大家掌握,大有用处
    require.context(arg1,arg2,arg3)
        arg1 - 读取文件的路径
        arg2 - 是否遍历文件夹子目录
        arg3 - 匹配文件名的正则
*/
    const requireComponent = require.context('.', false, /\.vue$/);
    console.log('requireComponent.keys():', requireComponent.keys()); // 打印加载到的文件名称
    requireComponent.keys().forEach(fileName => {
        const config = requireComponent(fileName); // 加载组件
        const componentName = changeStr(
            fileName.replace(/^\.\//, '').replace(/\.\w+$/, '') // ./child1.vue => Child1
        );
        console.log('componentName:', componentName);
        Vue.component(componentName, config.default || config); // 动态注册该目录下的所有.vue文件
    });
}

main.js

// 其他不相关代码省略
import { ComponentsLoader } from './views/components/loader';
Vue.use(ComponentsLoader);

xxx.vue 业务代码

<template>
    <div :class="$style.messageRoute">
        ... 此处省略 ...
        <ConfirmModal :confirmModalObj="confirmModalObj" :msg="confirmModalObj.msg" @iot-confirm="delConfirm" desc=""></ConfirmModal>
    </div>
</template>
<script>
// 此处不需要引入了
// import confirmModal from './components/confirmModal'
export default {
    name: 'contentArea',
    components: {
        // confirmModal,
    },
    data() {
        return {
         ... 此处省略 ...
        }
    }
}

vuex模块自动载入

原理和上面组件自动注册一样,也是使用了require.context的方法

代码

store/modules/count.js

const moduleA = {
    state: { count: 0 },
    mutations: {
        increment(state) {
            state.count++;
        }
    }
};
export default moduleA;

store/loader.js

/**
 * 将/store/modules/下的js 文件全部导入vuex中,而无需手动增加,模块名称以文件名命名
 */

const files = require.context('./modules', false, /\.js$/);
const modules = {};

files.keys().forEach(key => {
    modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default;
});

console.log('vuex-modules:', modules);
export default modules;

store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
import modules from './loader.js';  // 导入文件

Vue.use(Vuex);

const store = new Vuex.Store({
    modules
});

export default store;

main.js

import Vue from 'vue';
import App from './App.vue';
import store from './store/index.js';
... 省略其他代码 ...

new Vue({
    render: h => h(App),
    store
}).$mount('#app');

xxx.vue 业务代码

<template>
    <div>
       ...  ...
    </div>
</template>
<script>
export default {
    name: 'Main',
    mounted() {
        this.$store.commit('increment');  // 调用方法
    }
};
</script>