阅读 366

Vue 局部组件自动化注册

原版本

目录结构

界面有独属于自己的组件,在界面目录下新建components文件封装组件,方便复用和更改

image.png

组件管理

在index.js中,对组件进行统一管理并暴露出来,让界面的vue文件可以引入组件

//省略其他组件export default代码
export {
    default as layerTree
}
from './layerTree'



复制代码

界面引入

import { layerTree, numItem, slTable, areaInfoSwiper, colorLegend, animalDeta } from './components';
export default {
    //省略vue的data(),created()等部分 
    components: {
        layerTree, numItem, slTable, areaInfoSwiper, colorLegend, animalDeta
    }
}
复制代码

这样我门的界面就可以使用这些子组件了。

问题分析

但是这样每新增一个组件,就要在index.js中新增一个组件并暴露出去。或者组件的vue名字变动了,index里变一遍,引用的地方所有关联地方都要变,就太噩梦了,所以想着可不可以自动化注册组件并且暴露出去,这样即使新增了组件,变动组件名,都只需要在html中更改子组件的名称即可,心智负担大大减少。

版本优化

index.js(better)

//省略其他组件export default代码
// export {
//     default as layerTree
// }
// from './layerTree'

const contexts = require.context('./', false, /\.vue$/)
const components = []
let removeList = [] //要排除某个文件
contexts.keys().forEach(key => {
    const name = key.replace(/(\.\/|\.vue)/g, '')
    removeList.includes(name) ? '' : components[name] = resolve => require([`${key}`], resolve)

})
//暴露出数组对象
export default components
复制代码

require.context() 方法来创建自己的(模块)上下文,从而实现自动动态require组件。这个方法需要3个参数:要搜索的文件夹目录,是否还应该搜索它的子目录,以及一个匹配文件的正则表达式。

界面引入(better)

import components from './components';
export default {
    //省略vue的data(),created()等部分 
    components: {
        //...扩列符将数组对象成员全部暴露出来
        ...components
    }
}
复制代码

全局注册

附上全局注册版本

import Vue from 'vue'

function capitalizeFirstLetter(string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}

const requireComponent = require.context(
  '.', false, /\.vue$/
   //找到components文件夹下以.vue命名的文件
)

requireComponent.keys().forEach(fileName => {
  const componentConfig = requireComponent(fileName)

  const componentName = capitalizeFirstLetter(
    fileName.replace(/^\.\//, '').replace(/\.\w+$/, '')
    //因为得到的filename格式是: './baseButton.vue', 所以这里我们去掉头和尾,只保留真正的文件名
  )

  Vue.component(componentName, componentConfig.default || componentConfig)
})
复制代码

疑惑

其实关于局部的自动化注册,下面是另一个版本

function capitalizeFirstLetter(string) {
    return string.charAt(0).toUpperCase() + string.slice(1)
}

const requireComponent = require.context(
    '.', false, /\.vue$/
    //找到components文件夹下以.vue命名的文件
)

requireComponent.keys().forEach(fileName => {
        const componentConfig = requireComponent(fileName)
        const componentName = capitalizeFirstLetter(
            fileName.replace(/^\.\//, '').replace(/\.\w+$/, '')
        )
        //在遍历内部就将组件一个个暴露出来
        export {
            default as fileName
        }
        from componentConfig
    })
复制代码

遍历keys 然后分别export出去

就会引发'import' and 'export' may only appear at the top level的错误,按照网上的解决方案,我新建了.eslintrc.js

module.exports = {
    "env": {
        "browser": true,
        "es6": true,
        "node": true,
        "browser": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:vue/essential"
    ],
    "globals": {
        "Atomics": "readonly",
        "SharedArrayBuffer": "readonly"
    },
    "parserOptions": {
        "ecmaVersion": 2018,
        "sourceType": "module"
    },
    "plugins": [
        "vue"
    ], //其他的设置都是自动的
    "rules": {
        //就是这一句,禁用import和require必须出现在顶层作用域的验证规则
        "global-require": 0 //这里应该0代表off之前写错了写成了false
    }
};
复制代码

但是依旧报错,不清楚怎么解决,家人们知道怎么弄吗

image.png

思考

第一个可以使用的优化版本,其index暴露出来的是一个数组,而不是export default的形式,导致vue文件引入index的时候引入的是一个数组对象,没法对其进行重命名,index中暴露出来的名字叫什么,那引入的时候就得叫什么。如果是之后还有问题的遍历中export的优化版本,就可以使用import * as '新的名字' from 的形式进行重命名。两者相比,虽然一开始在indexjs中将名字写好没有太大的心智负担,但无疑没有后者灵活,所以还是想着后者的方法更加合适一点,而且可以按需引入。

最终版本

就,很难受,这个优化不做就很难受,你懂我意思吧。终于整出来了

index.js(final)

const contexts = require.context('./', false, /\.vue$/)
const components = []
let removeList = [] //要排除某个文件
contexts.keys().forEach(key => {
    const name = key.replace(/(\.\/|\.vue)/g, '')
    removeList.includes(name) ? '' : components[name] = resolve => require([`${key}`], resolve)

})
//由export default改为 export
export {
    components
}
复制代码

界面引入(final)

import { components as biodiversity_components } from '../biodiversity/components';
export default {
    //省略vue的data(),created()等部分 
    components: {
        ...biodiversity_components
    },
}
复制代码

1.export与export default均可用于导出常量、函数、文件、模块等

2.在一个文件或模块中,export、import可以有多个,export default仅有一个

3.通过export方式导出,在导入时要加{ },export default则不需要

所以我们使用export,从而在{}中对数组对象重命名

隐患

要是一个界面引入两个indexjs暴露出来的数组对象,并且分别对它们重命名之后,例如FirstComponents中有一个组件叫showModal,SecondComponents中有一个组件也叫showModal,这样后引入的组件就会把前面的组件冲掉,调用到的就是最后引入的showModal,那怎么办呢?这时候是要在indexjs里面分别暴露一次这个showModal子组件然后在引入的vue里面进行重名吗?还是说只需要一开始在命名这些子组件的时候就应该规避这种重命名现象吗?但好像这样太刻意,不够灵活了

尾声

一套操作下来,还是收获了很多的,希望以后能想出好的解决方案吧,也欢迎大家给点建议和指出错误

你来看,文章,我,觉得,很好,scar

文章分类
前端
文章标签