在 src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Layout from "@/views/layout/IndexView";
Vue.use(VueRouter);
const routes = [
{
path: "/sign_in",
component: () => import("@/views/auth/SignIn"),
meta: { title: "登录" },
},
// 无权限访问
{
path: "/401",
component: () => import("@/views/error-page/Page401View"),
meta: { title: "401" },
},
{
path: "/",
component: Layout,
children: [
{
path: "",
component: () => import("@/views/HomeView"),
meta: { title: "首页" },
},
{
path: "/users",
component: () => import("@/views/users/ListView"),
meta: { title: "用户列表" },
},
{
path: "/users/create",
component: () => import("@/views/users/CreateView"),
meta: { title: "新增用户" },
},
{
path: "/users/edit/:id",
component: () => import("@/views/users/EditView"),
meta: { title: "编辑用户" },
},
{
path: "/roles",
component: () => import("@/views/roles/ListView"),
meta: { title: "用户组列表" },
},
{
path: "/roles/create",
component: () => import("@/views/roles/CreateView"),
meta: { title: "新增用户组" },
},
{
path: "/roles/edit/:id",
component: () => import("@/views/roles/EditView"),
meta: { title: "编辑用户组" },
},
{
path: "/permissions",
component: () => import("@/views/permissions/ListView"),
meta: { title: "菜单与权限列表" },
},
],
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
新建 views/error-page/Page401View.vue
<template>
<div class="errPage-container">
<el-button icon="el-icon-arrow-left" class="pan-back-btn" @click="back">
返回
el-button>
<el-row>
<el-col :span="12">
<h1 class="text-jumbo text-ginormous">Oops!h1>
<h2>你没有权限去该页面h2>
<ul class="list-unstyled">
<li>或者你可以去:li>
<li class="link-type">
<router-link to="/"> 回首页 router-link>
li>
ul>
el-col>
el-row>
div>
template>
<script>
export default {
name: "Page401View",
methods: {
back() {
this.$router.go(-1);
},
},
};
script>
<style lang="scss" scoped>
.errPage-container {
width: 800px;
max-width: 100%;
margin: 100px auto;
.pan-back-btn {
background: #008489;
color: #fff;
border: none !important;
}
.pan-gif {
margin: 0 auto;
display: block;
}
.pan-img {
display: block;
margin: 0 auto;
width: 100%;
}
.text-jumbo {
font-size: 60px;
font-weight: 700;
color: #484848;
}
.list-unstyled {
font-size: 14px;
li {
padding-bottom: 5px;
}
a {
color: #008489;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
style>
1、新建 store/modules/permission.js
// 1、定义 state 用于存储 routers 路由列表
const state = () => ({
routers: [],
});
// 2、定义 mutations 用于修改路由列表数据
const mutations = {
SET_ROUTERS: (state, routers) => {
state.routers = routers;
},
};
// 3、定义 actions 用于获取路由数据
const actions = {};
// 4、导出
export default {
namespaced: true,
state,
mutations,
actions,
};
2、修改 src/store/index.js 代码
import Vue from "vue";
import Vuex from "vuex";
import auth from "./modules/auth";
import permission from "./modules/permission"; // 1、导入 permission
import getters from "@/store/getters";
Vue.use(Vuex);
export default new Vuex.Store({
getters,
modules: {
auth,
permission, // 2、注册 permission
},
});
1、修改 src/permission.js 代码
import router from "@/router";
import { getToken } from "@/utils/auth";
import store from "./store";
import { Message } from "element-ui";
router.beforeEach(async (to, from, next) => {
document.title = `${to.meta.title} - 长乐未央`;
const hasToken = getToken();
if (hasToken) {
if (to.path === "/sign_in") {
next({ path: "/" });
} else {
try {
// 1、判断路由是否已经生成了
const hasRouters =
store.getters.routers && store.getters.routers.length > 0;
// console.log(111, hasRouters);
if (hasRouters) {
next();
} else {
// 2、如果还没有路由,读取接口,获取路由列表数据
const { routers } = await store.dispatch("auth/getInfo");
// console.log(222, routers);
// 3、通过获取到的routers数据,去请求 modules/permission/generateRouters 函数,并传入 routers 路由数据
await store.dispatch("permission/generateRouters", routers);
}
} catch (error) {
await store.dispatch("auth/resetToken");
Message.error(error || "Has Error");
next("/sign_in");
}
}
} else {
if (to.path === "/sign_in") {
next();
} else {
next("/sign_in");
}
}
});


2、修改 store/modules/permission.js
const state = () => ({
routers: [],
});
const mutations = {
SET_ROUTERS: (state, routers) => {
state.routers = routers;
},
};
const actions = {
// 4、定义 generateRouters 函数,接收两个参数。commit用于提交mutations修改数据;routers是传过来的路由列表
generateRouters({ commit }, routers) {
console.log(commit);
console.log(333, routers);
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};

3、继续修改 store/modules/permission.js
import Layout from "@/views/layout/IndexView"; // 6、导入布局模板
const state = () => ({
routers: [],
});
const mutations = {
SET_ROUTERS: (state, routers) => {
state.routers = routers;
},
};
const actions = {
// 4、定义 generateRouters 函数,接收两个参数。commit用于提交mutations修改数据;routers是传过来的路由列表
generateRouters({ commit }, routers) {
console.log(commit);
// console.log(333, routers);
// 5、组装路由列表格式
const accessedRouters = {
path: "/",
component: Layout,
};
// 7、循环取出路由列表所需的参数值,如:path、component、meta
accessedRouters.children = routers.map((item) => ({
path: item.path,
component: () => import(`@/views/${item.component}`),
meta: { title: item.title },
}));
// console.log(444, accessedRouters.children);
// 8、最终提交给 mutations 进行修改
commit("SET_ROUTERS", accessedRouters);
return accessedRouters;
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};

4、执行动态添加路由,修改 src/permission.js 代码
import router from "@/router";
import { getToken } from "@/utils/auth";
import store from "./store";
import { Message } from "element-ui";
router.beforeEach(async (to, from, next) => {
document.title = `${to.meta.title} - 长乐未央`;
const hasToken = getToken();
if (hasToken) {
if (to.path === "/sign_in") {
next({ path: "/" });
} else {
try {
const hasRouters =
store.getters.routers && store.getters.routers.length > 0;
if (hasRouters) {
next();
} else {
const { routers } = await store.dispatch("auth/getInfo");
// 9、给请求结果赋值为 accessRoutes
const accessRoutes = await store.dispatch(
"permission/generateRouters",
routers
);
// 10、调用 router 实例里面的 addRoute 方法动态增加路由
router.addRoute(accessRoutes);
// 11、如有错误,跳转到401页面
router.addRoute({ path: "*", redirect: "/401" });
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true });
}
} catch (error) {
await store.dispatch("auth/resetToken");
Message.error(error || "Has Error");
next("/sign_in");
}
}
} else {
if (to.path === "/sign_in") {
next();
} else {
next("/sign_in");
}
}
});
5、修改 src/router/index.js 路由列表
import Vue from "vue";
import VueRouter from "vue-router";
import Layout from "@/views/layout/IndexView";
Vue.use(VueRouter);
const routes = [
{
path: "/sign_in",
component: () => import("@/views/auth/SignIn"),
meta: { title: "登录" },
},
{
path: "/401", // 无权限访问
component: () => import("@/views/error-page/Page401View"),
meta: { title: "401" },
},
{
path: "/",
component: Layout,
children: [
{
path: "",
component: () => import("@/views/HomeView"),
meta: { title: "首页" },
},
],
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
测试
此时页面都可以正常访问,功能也都是好的
修改 views/layout/components/SideBar.vue
<template>
<el-aside width="200px">
<el-col>
<el-menu
:router="true"
:default-active="activeMenu"
class="el-menu-vertical-demo"
>
<el-menu-item index="/">
<i class="el-icon-pie-chart">i>
<span slot="title">仪表盘span>
el-menu-item>
<el-submenu :index="menu.title" v-for="menu in menus" :key="menu.id">
<template slot="title">
<i :class="menu.icon">i>
<span>{{ menu.title }}span>
template>
<el-menu-item
:index="child.path"
v-for="child in menu.children"
:key="child.id"
>{{ child.title }}el-menu-item
>
el-submenu>
el-menu>
el-col>
el-aside>
template>
<script>
// 1、导入辅助函数 mapGetters
import { mapGetters } from "vuex";
export default {
// 3、打印所有菜单
// created() {
// console.log(this.menus);
// },
computed: {
// 2、把 menus 这个 Getters 映射过来,在模板中循环
...mapGetters(["menus"]),
// 4、动态选中当前路由
activeMenu() {
// console.log(this.$route.path); // 获取当前路径
return this.$route.path;
},
},
};
script>