Vue/React如何优雅的一劳永逸的注册路由及组件

原文链接: 本人掘金文章  假如图片看不清晰可前往掘金原文预览

官方文档: 组建注册 路由注册

未优化版: 在Vue官方文档 中,我们通过  Vue.component('MyComponentName', { /* ... */ })  的方式来进行全局组件注册,但如果需要全局注册的组件很多,这时代码就会变得比较臃肿,例如:

// 注册组件
import Component1 from './components/Component1'
import Component2 from './components/Component2'

// 方式1
Vue.component('Component1', Component1)
Vue.component('Component2', Component2)

// 方式2
const components = {
    Component1,
    Component2
}
Object.keys(components).forEach(key => {
    Vue.component(key, components[key])
})

// 注册路由
export default new Router({
  routes: [
    { // 登录页
      path: '/',
      name: 'Login',
      component: (resolve) => { require(['@/pages/Login'], resolve) }
    }]
})

优化版: webpack 提供的API神器 require.context() 可用来创建自己的(模块)上下文,具体打印看末尾

require.contex t函数接收三个参数:

  1. 要搜索的文件夹目录
  2. 是否还应该搜索它的子目录
  3. 以及一个匹配文件的正则表达式

一、先把我的目录结构及文件组成贴出来 (这是vue-cli3.0未使用typescript的版本)

 

接下来如何自动注册组件呢: 全局新建一个 utils目录下新建一个 global.js
// 获取所有vue文件
function getComponent() {
  return require.context('../views', true, /.vue$/);
}
// 首字母转换大写
function viewToUpperCase(str) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}
// 首字母转换小写
function viewToLowerCase(str) {
  return str.charAt(0).toLowerCase() + str.slice(1);
}
// 自动注册组件方法
export const vueComponent = () => {
  // 获取文件全局对象
  const requireComponents = getComponent();
  requireComponents.keys().forEach((fileSrc) => {
    const fileName = requireComponents(fileSrc);
    const file =  fileName.default;
    const componentName = file.name;
    // 是否自动注册组件依据每个文件里的 isComponent 属性  避免注册不用的组件
    if (file.isComponent) Vue.component(componentName, fileName.default || fileName);
  });
};

// 自动注册路由方法
export const vueRouters = () => {
  const routerList = [];
  const requireRouters = getComponent();
  requireRouters.keys().forEach((fileSrc) => {
    // 获取 components 文件下的文件名
    const viewSrc = requireRouters(fileSrc);
    console.log(viewSrc);
    const file =  viewSrc.default;
    // 首字母转大写
    const vueRouterUpper = viewToUpperCase(file.name);
    // 首字母转小写
    const vueRouterLower =  viewToLowerCase(file.name);
    const fileNameSrc = fileSrc.replace(/^.//, '');
    // 是否自动注册路由依据每个文件里的 isRouter 属性 避免注册不用的路由
    if (file.isRouter) {
      // 注册路由
      routerList.push({
        path: `/${vueRouterLower}`,
        name: `${vueRouterUpper}`,
        component: () => import(`@/views/${fileNameSrc}`),
      });
    }
  });
  console.log(routerList);
  return routerList;
};

引入方式

 

二、这是 vue-cli3.0 使用 typescript 的版本, 不同的是 下 global.ts 需要增加类型,及文件设置属性的方法不用, 且获取上下文的时候是在 options

global.ts 修改为
import Vue from 'vue';

// 获取所有vue文件
function getComponent() {
  return require.context('../views', true, /.vue$/);
}
// 首字母转换大写
function viewToUpperCase(str: string) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}
// 首字母转换小写
function viewToLowerCase(str: string) {
  return str.charAt(0).toLowerCase() + str.slice(1);
}
export const vueComponent = () => {
  // 获取文件全局对象
  const requireComponents = getComponent();
  requireComponents.keys().forEach((fileSrc: string) => {
    const fileName = requireComponents(fileSrc);
    const file =  fileName.default.options;
    const componentName = file.name;
    if (fileName.default.isComponent) { Vue.component(componentName, fileName.default || fileName) };
  });
};
// 获取路由文件
export const vueRouters = () => {
  const routerList: any = [];
  const requireRouters = getComponent();
  requireRouters.keys().forEach((fileSrc: string) => {
    // 获取 components 文件下的文件名
    const viewSrc = requireRouters(fileSrc);
    console.log(viewSrc);
    const file =  viewSrc.default.options;
    // 首字母转大写
    const vueRouterUpper = viewToUpperCase(file.name);
    // 首字母转小写
    const vueRouterLower =  viewToLowerCase(file.name);
    // 设置路由路劲
    const fileNameSrc = fileSrc.replace(/^.//, '');
    // 是否自动注册路由依据每个文件里的 isRouter 属性 避免注册不用的路由
    if (viewSrc.default.isRouter) {
      // 注册路由
      routerList.push({
        path: `/${vueRouterLower}`,
        name: `${vueRouterUpper}`,
        component: () => import(`@/views/${fileNameSrc}`),
      });
    }
  });
  console.log(routerList);
  return routerList;
};
vue 文件修改为
<script lang="ts">
  import Button from '@/components/Button.vue';
  import { Component, Prop, Vue } from 'vue-property-decorator';
  @Component({
    name: 'About',
    components: { Button },
  })
  export default class About extends Vue {
    static isRouter = true; // tslint:disable-line
    static isComponent = true; // tslint:disable-line
    private handleClick() {
      console.log('button');
    }
  }
</script>
require.context() 获取文件对象:
  1. javascript

 

  2. typescript 版本
react 版本不同的只是 模板文件不同,有需要的朋友可以留言我
有不对之处及有更好的方法欢迎留言指正
原文地址:https://www.cnblogs.com/ljx20180807/p/11720796.html