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函数接收三个参数:
- 要搜索的文件夹目录
- 是否还应该搜索它的子目录
- 以及一个匹配文件的正则表达式
一、先把我的目录结构及文件组成贴出来 (这是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 版本不同的只是 模板文件不同,有需要的朋友可以留言我
有不对之处及有更好的方法欢迎留言指正