你还在一个个路由文件引入而烦恼吗
你还被别人说,你只是一个只会ctrl+ c ctrl +v
的码仔吗
可是
做个与世无争的垃圾不好吗
global.ts
// 可以把检测的类型去掉,转成js
// 关键在于 require.context
// 暴露了两个方法 在组件声明两个变量来区别状态 isRouter isComponent
import Vue from "vue";
// 获取component下所有vue文件
function getComponent() {
return require.context("../components", true, /\.vue$/);
}
// 获取views下所有vue文件
function getRouterComponent() {
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 = () => {
// 获取文件全局对象 isComponent
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 = () => {
// 获取路由文件 isRouter
const routerList: any = [];
const requireRouters = getRouterComponent();
requireRouters.keys().forEach((fileSrc: string) => {
// 获取 components 文件下的文件名
const viewSrc = requireRouters(fileSrc);
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}`),
meta: {
index: 1
}
});
}
});
return routerList;
};
export default class Home extends Vue {
static isRouter: boolean = true;
}
export default class Home extends Vue {
static isComponent: boolean = true;
}
组件在main.js使用
import { vueComponent } from "./utils/global";
vueComponent()
路由在router.js使用
import { vueRouters } from "../utils/global";
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
redirect: "/home"
},
...vueRouters()
]
});
简单的路由,组件模块是可以这样秀一波了
我原本以为:牛* 啊,好* 啊。以后项目就这样搞。可是,今天作项目的时候,我二级路由,参数:id
这些方案怎么破
一切又感觉回到了起点(组件注册可以)
在git上找到两个,附上地址
https://github.com/zhangOking/vuecli3plugin-generatererouter
https://github.com/18692959234/free-router
以下是其中一个上大佬的,仿照nuxt.js
route/route.js
// import Vue from 'vue'
let files = require.context('../pages', true, /\.vue$/) // 根据目录结构去搜索文件
let filesKey = files.keys() // 获取整个目录结构
console.log(filesKey)
/**
* 获取路由name
* @param {*} file type:string (文件完整的目录)
*/
const getRouteItemName = (file) => {
let match = file.match(/\/(.+?)\.vue$/)[1] // 去除相对路径与.vue
let res = match.replace(/_/ig, '').replace(/\//ig, '-') // 把下划线去除, 改变/为-拼接
return res
}
/**
* 获取路由path
* @param {*} file String (目录,一级路由则为完整目录,多级为自身目录名称)
*/
const getRouteItemPath = (file) => {
return file.replace('/index.vue', '').replace('index.vue', '').replace('vue', '').replace(/_/g, ':').replace(/\./g, '')
}
/**
* 注册组建
* @param {*} componentConfig (即为调用files方法得出的componentConfig)
*/
// const registerComponent = (componentConfig) => Vue.component(componentConfig.default.name || componentConfig.default, componentConfig.default || componentConfig)
/**
* 校验目录下是否有其他文件,注意((?!${name}).)是因为要查询的目录有可能为name/name.vue,而这样可能会导致误判有无children,所以要匹配非name。
* @param {*} file type:string (当前目录路径)
* @param {*} name type:string (目录的文件名 默认等于file参数)
*/
const hasfile = (file, name = file) => new RegExp(file + `/((?!${name}).)`)
/**
* 校验.vue文件
* @param {*} file type:string (当前目录路径)
*/
const hasVue = (file) => new RegExp(file + '.vue')
/**
* 构建路由
* @param {*} map type:Object
*/
const getRoutes = (map) => {
let res = []
for (let key in map) { // 遍历对象
let level = map[key] // 取出对应value
let text = level.join('@') // 用@把分级数组拼接,这样只是为了方便查找
let expr1 = hasfile(key) // 校验规则,有无子文件
let expr2 = hasVue(key) // 校验规则,有无vue文件
let route = {} // 初始化route
if (text.match(expr1) && text.match(expr2)) { // 有children的route
let max = Math.max(...level.map(v => v.match(/\/(.+?).vue$/)[1].split('/').length)) // 找目录里最深的层级数
let i = 0 // 标记层级
while (i++ < max) { // 按层级来搭建route
level.forEach((item) => {
let wipeOfVue = item.match(/\/(.+?).vue$/)[1] // 匹配纯路径,去除相对路径与.vue
let classArray = wipeOfVue.split('/') // 切割为了方便操作
let len = classArray.length // 深度
if (len === i) {
if (i === 1) { // 如果为第一层,则必带有children
route = {
component: files(item).default,
path: getRouteItemPath(item),
children: []
}
} else {
let file = item.match(/(.+?)\.vue$/)[1] // 只匹配目录下.vue之前的路径
let name = classArray[len - 1] // 获取每个路径下具体的文件名
let iteration = classArray.slice(0, len - 1) // 截取文件路径
let childRoute = {
component: files(item).default,
path: getRouteItemPath(name)
}
// 从文件的目录下搜索有无子文件,有子文件代表有children属性。 否则无,则直接给route增加name属性
text.match(hasfile(file, name)) && text.match(hasVue(file)) ? childRoute.children = [] : childRoute.name = getRouteItemName(item)
// 通过截取的目录找到对应的parent
let parent = iteration.reduce((map, current, index) => {
let path = index === 0 ? getRouteItemPath(`/${current}.vue`) : getRouteItemPath(`${current}.vue`)
return map.filter(v => v.path === path)[0].children
}, [route])
parent && parent.push(childRoute)
}
}
})
}
res.push(route) // 添加route对象
} else { // 没有children,直接遍历插入
level.forEach(item => {
route = {
component: files(item).default,
name: getRouteItemName(item),
path: getRouteItemPath(item)
}
res.push(route) // 添加route对象
})
}
}
return res // 返回整个route对象
}
/**
* 以一级文件或者文件夹 分类获取路由
*/
const createClassify = () => {
let map = filesKey.reduce((map, cur) => {
let dislodge = cur.match(/\/(.+?)\.vue$/)[1] // 只匹配纯文件名的字符串
let key = dislodge.split('/')[0]; // 拿到一级文件的名称
(map[key] || (map[key] = [])).push(cur)
return map
}, {})
return getRoutes(map)
}
const freeRoute = createClassify()
console.log(freeRoute)
const routes = [
...freeRoute
]
export default routes
route/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router