基于 Vue 脚手架遍历目录文件自动生成路由
require.context
你还可以使用 require.context() 方法来创建自己的(模块)上下文。
你可以给这个方法传 3 个参数:要搜索的文件夹目录,是否还应该搜索它的子目录,以及一个匹配文件的正则表达式。
webpack 会在构建的时候解析代码中的 require.context() 。
思路
自定义一个菜单数组用来循环动态生成路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46/**
* 文件创建的时候,如果当前的菜单下面还有子菜单,需要在该文件夹下面新建一个 index.vue 的文件,用来跳转路由
* 菜单命名的格式如下
*/
export const menus = [
{
key: "menu1",
label: "一级菜单1",
icon: "",
},
{
key: "menu2",
label: "一级菜单2",
icon: "",
},
{
key: "menu3",
label: "一级菜单3",
icon: "",
children: [
{
key: "menu3_1",
label: "一级菜单3_1",
icon: "",
children: [
{
key: "menu3_1_1",
label: "一级菜单3_1_1",
icon: "",
},
],
},
{
key: "menu3_2",
label: "一级菜单3_2",
icon: "",
},
],
},
{
key: "menu4",
label: "未开发页面演示",
icon: "",
},
];核心代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
export const routes: any[] = [];
const viewContext = require.context("./views", true, /\.vue$/);
const cache: { [key: string]: object } = {};
viewContext.keys().forEach((key) => cache[key] = viewContext(key).default);
interface RouterObj {
path: string;
name: string;
component?: object;
[propName: string]: any;
}
interface Menu {
key: string;
label: string;
icon?: string;
[propName: string]: any;
}
const menu2router = (menu: Menu, parent: RouterObj, index: number, thisRoutes: any[]) => {
let isFind = false;
const route: RouterObj = {
path: parent.path + "/" + menu.key,
name: menu.label,
};
if (menu.children && menu.children.length > 0) {
const routeFilePath = route.path + "/index.vue";
let fileComponent = null;
for (const key of Object.keys(cache)) {
if (key.indexOf(routeFilePath) !== -1) {
fileComponent = cache[key];
break;
}
}
thisRoutes[index] = {
path: "/" + menu.key,
name: menu.label,
component: fileComponent,
children: [],
};
for (let i = 0, j = menu.children.length; i < j; i++) {
menu2router(menu.children[i], route, i, thisRoutes[index].children);
}
}
const routePath = route.path + "/" + (menu.key || "index") + ".vue";
for (const key of Object.keys(cache)) {
if (key.indexOf(routePath) !== -1) {
isFind = true;
const obj: RouterObj = {
path: route.path,
name: route.name,
component: cache[key],
};
thisRoutes.push(obj);
break;
}
}
if (!isFind) {
thisRoutes.push({
path: route.path,
name: route.name,
component: notFind,
});
}
};
export const getRouter = (menusArr: any[]) => {
menusArr.forEach((menu: Menu, index: number) => {
menu2router(menu, {path: "", name: ""}, index, routes);
});
routes.push({
path: "/",
redirect: routes[0].path,
});
return new Router({
mode: "history",
base: process.env.BASE_URL,
routes,
});遍历生成菜单
以 iview 组件库中的菜单为例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33<template lang="pug">
Menu(:active-name="activeName" theme="dark" width="auto")
template(v-for="(menu, index) in menus")
MenuItem(v-if="!menu.children" :name="menu.key" :to="'/' + menu.key") {{menu.label}}
Submenu(v-else :name="menu.key")
template(slot="title") {{menu.label}}
template(v-for="(secondMenu, secondMenuIndex) in menu.children")
MenuItem(v-if="!secondMenu.children" :name="secondMenu.key" :to="'/' + menu.key + '/' + secondMenu.key") {{secondMenu.label}}
Submenu(v-else :name="secondMenu.key")
template(slot="title") {{secondMenu.label}}
MenuItem(v-for="(thirdMenu, thirdIndex) in secondMenu.children" :key="thirdIndex" :name="thirdMenu.key" :to="'/' + menu.key + '/' + secondMenu.key + '/' + thirdMenu.key") {{thirdMenu.label}}
</template>
<script lang="ts">
import {Vue} from "vue-property-decorator";
import {sessionMenus} from "@/check_session";
export default class Menus extends Vue {
activeName: string = "";
menus: any[] = sessionMenus.menus;
mounted() {
const href = window.location.href;
const hrefArr = href.split("/");
this.activeName = hrefArr[hrefArr.length - 1];
}
}
</script>
<style lang="stylus" scoped>
</style>
项目地址
本站点所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 吕钒的后花园!