文章目录
- 前言
- 一、什么是动态路由
- 二、以 后台管理系统路由权限配置为例
- 静态路由配置
- 动态路由配置
- 总结
- `如有启发,可点赞收藏哟~`
前言
其几天记录了根据目录接口动态配置vue的静态路由
本文结合addRoute
记录下配置动态路由
一、什么是动态路由
动态路由是根据实际配置数据、不同链接参数等动态的添加路由或者删除路由的总称
动态路由主要通过两个函数实现。
router.addRoute()
router.removeRoute()
。- 它们只注册一个新的路由,也就是说,如果新增加的路由与当前位置相匹配,就需要你用 router.push() 或 router.replace() 来手动导航,才能显示该新路由。
二、以 后台管理系统路由权限配置为例
废话不说,直接上代码,以下代码简单记录了在登录获取用户信息后动态添加当前用户路由权限等配置
先看效果
静态路由配置
动态路由配置
- 新建
router/permission.ts
文件
import router from "@/router";
import { UserStore } from "@/stores/modules/user";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import { storeToRefs } from "pinia";
NProgress.configure({ showSpinner: false }); // 进度条
/**
* 跳转路由前
*/
router.beforeEach(async(to, from, next) => {
NProgress.start();
const { userInfo } = storeToRefs(UserStore())
if (Object.keys(userInfo.value).length) {
// 未匹配到任何路由,跳转404
if (to.matched.length === 0) {
NProgress.done();
from.name ? next({ name: from.name }) : next("/error");
} else {
NProgress.done();
next();
}
} else {
try {
const { setUserInfo, filterAsyncRoutes } = UserStore()
await setUserInfo()
const accessRoutes = await filterAsyncRoutes()
if (accessRoutes) {
accessRoutes.forEach(route => {
router.addRoute(route)
});
}
if (to.meta.title) {
document.title = to.meta.title as string
}
next({ ...to, replace: true });
} catch (error){
// TODO 移除 token 并跳转登录页
next(`/login?redirect=${to.path}`);
NProgress.done();
}
}
})
/**
* 路由完成后
*/
router.afterEach((to) => {
if (!to.meta.skeleton) {
}
if (!to.meta.background) {
}
NProgress.done();
})
- 新建
stores/modules/user.ts
import { SUCCESS_CODE } from "@/const/base/result-code";
import type { MenuType } from "@/interface/menu";
import { getMenu, getUserInfo } from "@/server/user";
import type { getUserInfoDataType } from "@/server/user/interface";
import { ElMessage } from "element-plus";
import { defineStore } from "pinia";
import { reactive, ref } from "vue";
import type { RouteRecordRaw } from "vue-router";
const modules = import.meta.glob("../../views/contents-pages/**/index.ts");
const systemModules = import.meta.glob("../../views/system-pages/**/index.ts");
const { SIS_STORE_NAME } = import.meta.env;
export const UserStore = defineStore(`${SIS_STORE_NAME}-user-store`, () => {
/**
* 用户信息
*/
const userInfo = ref({} as getUserInfoDataType)
/**
* 侧边栏数据
*/
const menu: Array<MenuType> = reactive([])
/**
* 获取用户信息
* @returns
*/
const setUserInfo = async() => {
const response = await getUserInfo()
if (response.code !== SUCCESS_CODE) {
ElMessage.error(response.msg)
return false
}
userInfo.value = response.data
return true
}
const getRoutes = (route: RouteRecordRaw[]) => {
const asyncRoutes: RouteRecordRaw[] = [];
route.forEach(item => {
const tmpRoute = {
...item,
}
const component = modules[`../../views/contents-pages/${item.component}.ts`];
if (component) {
tmpRoute.component = component;
} else {
tmpRoute.component = systemModules[`../../views/system-pages/error/index.ts`];
}
if (item.children) {
tmpRoute.children = getRoutes(item.children)
}
asyncRoutes.push(tmpRoute)
});
return asyncRoutes
}
/**
* 获取路由配置
* @returns
*/
const filterAsyncRoutes = async() => {
const response = await getMenu()
if (response.code !== SUCCESS_CODE) {
ElMessage.error(response.msg)
return false
}
return getRoutes(response.data)
}
return {
userInfo,
menu,
setUserInfo,
filterAsyncRoutes
};
});
- 新建
stores/index.ts
import type { App } from "vue";
import { createPinia } from "pinia";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const store = createPinia().use(piniaPluginPersistedstate);
// 全局注册 store
export function setupStore(app: App<Element>) {
app.use(store);
}
export { store };
- main.js
import { createApp } from "vue";
import App from "./App/index.vue";
import router from "./router";
import "@/router/permission";
import { setupStore } from "./stores";
const app = createApp(App);
// 全局注册 状态管理(store)
setupStore(app)
app.use(router);
app.mount("#app");
简单配置个模拟数据实验下
根目录 新建 mock/menu.ts
和 mock/userInfo.ts
- menu.ts
import type { MockMethod } from "vite-plugin-mock";
export default [
{
url: "/api/usr/menu",
timeout: 200,
method: "get",
response: ({ query }) => {
return {
code: 200,
data: [
{
// 路由
path: "/",
// 组件路径
component: "layout/index",
// 重定向路由
redirect: "/index",
// 路由名称
name: "Index",
children: [
{
path: "index",
component: "index/index",
name: "Index",
meta: {
title: "首页",
icon: "index",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
]
},
{
// 路由
path: "/system",
// 组件路径
component: "layout/index",
// 重定向路由
redirect: "/system/user",
// 路由名称
name: "/system",
meta: {
// 当前路由标题
title: "系统管理",
// 当前路由图标
icon: "system",
// 是否在menu隐藏
hidden: false,
// 权限等级
roles: ["ADMIN"],
},
children: [
{
path: "user",
component: "system/user/index",
name: "User",
meta: {
title: "用户管理",
icon: "user",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "role",
component: "system/role/index",
name: "Role",
meta: {
title: "角色管理",
icon: "role",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "menu",
component: "system/menu/index",
name: "Menu",
meta: {
title: "菜单管理",
icon: "menu",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "dict",
component: "system/dict/index",
name: "Dict",
meta: {
title: "字典管理",
icon: "dict",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
],
},
{
// 路由
path: "/log",
// 组件路径
component: "layout/index",
children: [
{
path: "log",
component: "log/index",
name: "Log",
meta: {
title: "日志",
icon: "log",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
]
},
],
msg: "OK",
};
},
},
] as MockMethod[];
- userInfo.ts
import type { MockMethod } from "vite-plugin-mock";
export default [
{
url: "/api/usr/userInfo",
timeout: 200,
method: "get",
response: ({ query }) => {
return {
code: 200,
data: {
userId: 1,
userName: "admin",
nickName: "系统管理员",
avatar: "xxx.gif",
roles: ["admin"],
operationPermissions: [
"sys:menu:delete",
"sys:menu:add",
"sys:menu:edit",
"sys:user:add",
"sys:user:edit",
"sys:user:delete",
"sys:user:reset_pwd",
"sys:dict_type:add",
"sys:dict_type:edit",
"sys:dict_type:delete",
"sys:dict:add",
"sys:dict:edit",
"sys:dict:delete",
"sys:role:add",
"sys:role:edit",
"sys:role:delete",
"sys:dept:add",
"sys:dept:edit",
"sys:dept:delete",
],
},
msg: "OK",
};
},
},
] as MockMethod[];