基于vue+element,把静态路由改为动态路由
修改动态路由的过程
第一步:修改理由配置文件,只留下login, router/index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router);
const commonRoutes = [
{
path: '/login',
type: 'login',
component: () => import('@/views/login'),
}
];
const createRouter = () => new Router({
linkActiveClass: 'active',
routes: commonRoutes
});
const router = createRouter()
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher
}
export default router
第二步:加工后台返回的json,成路由,utils/index.js
import {resetRouter } from '../router'
/**
* 合并远程路由到本地路由
* @param: subList [Array] 远程路由列表
* @param: routes [Array] 本地路由列表
* */
export function mergeRoutes(subs) {
//console.log(subs);
let str1,str2,str3,str4 = [];
if(subs){
for (let i = 0; i < subs.length; i++) {
str3 = [];
//如果还有下一层先进去
if(subs[i].children && subs[i].children.length > 0){
let list1 = subs[i].children;
for(let x = 0; x < list1.length; x++){
str2 = [];
if(list1[x].external == "1" ){//说明是外部链接,需要自己拼装
//如果path=/blank,说明是空白页,需要另外处理
if(list1[x].path == '/blank'){
let temp = {
path : list1[x].path,
name : list1[x].name,
menuShow : list1[x].menuShow == '1'? true: false,
component: () => import(`@/views/nav/leftNav`),
iconCls: list1[x].iconCls,
meta: {
apiActiveMenu : list1[x].meta
},
leaf: list1[x].leaf == '1'? true: false,
children: [
{
path : list1[x].path,
name : list1[x].name,
menuShow : list1[x].menuShow == '1'? true: false,
component: () => import(`@/views${list1[x].component}`),
}
],
};
str3.push(temp);
}else{
let temp = {
path : list1[x].path,
name : list1[x].name,
menuShow : list1[x].menuShow == '1'? true: false,
component: () => import(`@/views/nav/leftNav`),
iconCls: list1[x].iconCls,
meta: {
apiActiveMenu : list1[x].meta
},
leaf: list1[x].leaf == '1'? true: false,
external: list1[x].external == '1'? true: false,
children: [
{
path : list1[x].path,
name : list1[x].name,
menuShow : list1[x].menuShow == '1'? true: false,
component: () => import(`@/views/nav/rightC`),
}
],
};
str3.push(temp);
}
//跳出本次循环
continue;
}
else if(list1[x].children && list1[x].children.length > 0){
let list2 = list1[x].children;
for(let y = 0; y< list2.length; y++){
str1 = [];
if(list2[y].children && list2[y].children.length >0){
let list3 = list2[y].children;
for(let z = 0 ; z < list3.length; z++){
let temp = {
path : list3[z].path,
name : list3[z].name,
menuShow : list3[z].menuShow == '1'? true: false,
component: () => import(`@/views${list3[z].component}`),
meta: {
apiActiveMenu : list3[z].meta
},
leaf: list3[z].leaf == '1'? true: false,
};
str1.push(temp);
}
}
let temp = {
path : list2[y].path,
name : list2[y].name,
menuShow : list2[y].menuShow == '1'? true: false,
component: () => import(`@/views${list2[y].component}`),
children: str1,
meta: {
apiActiveMenu : list2[y].meta
},
leaf: list2[y].leaf == '1'? true: false,
};
str2.push(temp);
}
}
//不要问我为什么前端这么玩,后端不改,只有前端改,以后会是个天坑
if(str2.length>0){//如果上一层leaf是true,这一层的第一个想办法排序为true
if(!str2[0].menuShow){
var obj={} ;
for(var r = 0 ; r< str2.length ;r++){
if(str2[r].menuShow){//和第一个换位
obj = str2[r];
str2[r] = str2[0];
str2[0] = obj;
break;
}
}
}
}
let temp = {
path : list1[x].path,
name : list1[x].name,
menuShow : list1[x].menuShow == '1'? true: false,
component: () => import(`@/views${list1[x].component}`),
children: str2,
iconCls: list1[x].iconCls,
meta: {
apiActiveMenu : list1[x].meta
},
leaf: list1[x].leaf == '1'? true: false,
};
str3.push(temp);
}
}
//拼接的时候,有一个bug,就是在第一层subs中,定义的重定向redirect
//指定的路径,如果在路由中不存在,需要重新定义值
let redirect = subs[i].redirect;
let tag = false;//如果路径在路由中存在true
if(!tag){//说明需要设置默认的跳转路径redirect值
if(subs[i].children[0].leaf == "0"){//说明是菜单,需要进入下一层
if(subs[i].children[0].children[0].leaf == "0"){//说明是菜单,需要进入下一层
var arr = subs[i].children[0].children[0];
if(arr.leaf == "0"){
for(var e = 0 ; e<arr.children.length; e++){
if(arr.children[e].menuShow == '1' && arr.children[e].leaf == '1'){
// console.log(arr.children[e]);
redirect = arr.children[e].path;
break;
}
}
}else{
redirect = arr.path;
}
}else{
var arr = subs[i].children[0].children;
for(var t = 0 ;t < arr.length ; t++){
if(arr[t].menuShow == '1'){
redirect = arr[t].path;
break;
}
}
}
}else{
redirect = subs[i].children[0].path;
}
}
console.log(redirect);
let temp = {
path : subs[i].path,
name : subs[i].name,
menuShow : subs[i].menuShow == '1'? true: false,
component: () => import(`@/views${subs[i].component}`),
children: str3,
iconCls: subs[i].iconCls,
redirect: redirect,
meta: {
apiActiveMenu : subs[i].meta
},
leaf: subs[i].leaf == '1' ? true: false,
};
str4.push(temp);
}
}
str4.push({
path: '*',
component: () => import('@/components/404.vue')
});
return str4;
}
/**
* routes 要添加的路由
* 因为addRoutes()会重复添加路由,自定义的方法先去
* 初始化再添加避免重复添加
*/
export function selfaddRoutes(routes) {
router.matcher = new Router().matcher;
router.addRoutes(routes);
}
export function resetTokenAndClearUser() {
// 退出登陆 清除用户资料
sessionStorage.clear();
// 重设路由
resetRouter()
}
第3步:路由的一些判断,解决了路由的重复添加的问题,api/premission.js
import router from '@/router/index'
import store from '@/store/index'
import { mergeRoutes, resetTokenAndClearUser } from '@/utils'
//防止重复添加动态路由
let hasMenus = false;
// 拦截登录,session验证
router.beforeEach((to, from, next) => {
if(sessionStorage.getItem("token")){
if(to.path === '/login'){
next();
}else{
if(hasMenus){
next();
}else{
try {
const menus = JSON.parse(sessionStorage.getItem("menus"));
const routes = mergeRoutes(menus);
router.options.routes = router.options.routes.concat(routes);
router.addRoutes(router.options.routes);
hasMenus = true
next({path: to.path})
} catch (error) {
resetTokenAndClearUser()
next(`/login?redirect=${to.path}`)
}
}
}
}else{
hasMenus = false
sessionStorage.clear();
if(to.path === '/login'){
next();
}else{
next(`/login?redirect=${to.path}`)
}
}
})
router.onError((error) => {
const pattern = /Loading chunk (\d)+ failed/g;
const isChunkLoadFailed = error.message.match(pattern);
const targetPath = router.history.pending.fullPath;
if (isChunkLoadFailed) {
router.replace(targetPath);
}
});
第四步,把components/nav复制到views下
接下来,就是对于路由的配置。
这里需要注意的几个点,搞不清路由的配置就会出现问题。
类型中,有栏目、目录、菜单,先说清楚他们的区别
我们新增资源的时候,其实,就是区分是目录还是菜单。如果是最底层就是菜单,我会在路由配置中加入leaf:true。
第二点, 以商品招标为例,下面是静态的路由,我们动态路由应该怎么配置
{
path: '/tendersManager',
type: 'enterprise',
name: 'tenders',
redirect: '/tendersManager/tenderscenter',
component: Home,
menuShow: true,
meta:{
name:"商品招标"
},
children: [
{
path: '/tendersManager/tenderscenter',
component: LeftNav,
name: 'tenderscenter', // 当前路由的name
leaf: true, // 只有一个节点
iconCls: 'iconfont icon-home', // 图标样式class
menuShow: true,
children: [
{ path: '/tendersManager/tenderscenter', component: TenderCenter, name: '商品招标中心', menuShow: true }
]
},
{
path: '/tendersManager/missionmanager',
component: LeftNav,
name: '商品招标管理',
iconCls: 'el-icon-menu',
menuShow: true,
children: [
{ path: '/tendersManager/missionmanager', component: TenderMisssion, name: '招标任务管理', menuShow: true },
{ path: '/tendersManager/missionmanager/add', component: TenderAdd, name: '新建招标任务', menuShow: false,
meta:{
apiActiveMenu: '/tendersManager/missionmanager/add'
}
},
{ path: '/tendersManager/missionmanager/detail', component: TenderDetail, name: '查看', menuShow: false,
meta:{
apiActiveMenu: '/tendersManager/missionmanager/detail'
}
},
]
},
]
},
其中需要注意,招标任务管理中有俩个按钮
分别对应的俩个页面,这个时候需要去配置路由,我为了方便判断,需要把查询和新增的路由配置在【招标任务管理】同级下。