公司项目做整理需要将前端vue项目菜单修改成动态菜单+动态路由。
1.动态路由
了解需求后查看了package.json使用的是Vue.js 官方的路由管理器:vue-router。
1. 查看vue-router官方文档发现vue-router有 添加新路由规则的函数,函数有三个:
router.addRoutes(routes: Array<RouteConfig>)
动态添加更多的路由规则。参数必须是一个符合 routes
选项要求的数组。不过现已废弃。那我也就放弃了使用这个函数。
addRoute(route: RouteConfig): () => void
添加一条新路由规则。如果该路由规则有 name
,并且已经存在一个与之相同的名字,则会覆盖它。
addRoute(parentName: string, route: RouteConfig): () => void
添加一条新的路由规则记录作为现有路由的子路由。如果该路由规则有 name
,并且已经存在一个与之相同的名字,则会覆盖它。
分析:
可以看到第二个函数和第三个函数都是只能添加一条路由规则。 区别在于:第一个函数是新建或者覆盖已有的,第二个函数相当于在已有的路由父级中添加子路由。提供父路由的name即可。
2. 继续在文档中找到并查看RouteConfig对象,即动态添加路由方法我们需要传什么。如下图:
3. 我们需要的东西都有了,就可以开始写代码了,代码如下:
let list = res.object; //后端返回的需要添加的路由数组
list.forEach(obj=>{
//动态添加路由
//插入路由
this.$router.addRoute("home",{ //如果不是子组件只需要传后面的对象
name: obj.menuNo, //指定名称
path: obj.path, //访问路径
component: () => import('@/page'+obj.vuePath+'.vue') //需要显示的view。将组件用引进来
});
});
注意: 这样虽然可以实现但是会出现点击F5或手动刷新页面时出现404。 刷新会导致增加的动态路由失效,实际相当于重新读了一遍路由的配置。
解决bug思路: 每次跳转路由时判断是否是刷新。如果是刷新我们在动态增加一次路由。 路由数据可以存在sessionStorage中。
解决主要函数: 通过官方文档可以看到vue-router提供了全局前置守卫: router.beforeEach
方法有了,动手改造如下:
之前的代码修改如下:
let list = res.object;
window.sessionStorage.setItem("routerList",JSON.stringify(list)); //存入sesionStorage中
路由.js添加如下代码:
let isRefresh = true;
//挂载路由导航守卫
router.beforeEach((to ,from ,next ) => {
//to 将要访问的路径
//from 代表从哪个路径跳转而来
//next 是一个函数,表示放行,使用方式next()或者next('/xxxx')强制跳转到某个页面
if(to.path === '/login') return next();
//先获取token
const tokenStr = window.sessionStorage.getItem('token'); //判断是否登录 这里改成你自己的逻辑
if(!tokenStr) return next('/login');
if(isRefresh){ //这里是判断了是否是刷新和第一次登录 因为只有第一次添加动态路由和刷新才会使变量初始化
let routerJson = window.sessionStorage.getItem('routerList'); //取出路由数据
let routerList = JSON.parse(routerJson);
if(routerJson === null || routerJson === ""){
return next();
}
isRefresh = false;
routerList.forEach(menu =>{
//动态添加路由
//插入路由
router.addRoute("home",{
name: menu.menuNo,
path: menu.menuPath,
component: () => import('@/page'+menu.menuPath+'.vue') //将组件用引进来
});
});
return next({...to, replace: true}); //跳转
}
next();
})
这样就可以解决F5刷新页面时空白或404的问题了!
2.动态菜单
这里我们是基于elementUI的框架搭建。
动态菜单主要的就是查数据动态渲染。如果你的项目是两级或三级菜单直接用for循环就可以。但如果你的是四级五级菜单循环太冗余。推荐递归实现。
递归实现方法:
递归:子程序(或函数)直接调用自己或通过一系列调用语句间接调用自己。
1. 找出自己也是循环使用的代码,自建一个组件
<template>
<div>
<!-- 遍历菜单 -->
<template v-for="obj in objList">
<template v-if="item.children">
<!-- 第一层 含有子菜单 -->
<el-submenu :index="obj .menuPath" :key="obj .menuPath">
<template slot="title">
<i :class="obj .menuIcon"></i>
<span >{{ obj .menuName }}</span>
</template>
<menu-list :objList ="obj .children" ></menu-list><!--递归调用-->
</el-submenu>
</template>
<!-- 第一层 不含子菜单 -->
<template v-else>
<el-menu-item :index="obj .menuPath" :key="obj .menuPath">
<template slot="title">
<i :class="obj .menuIcon"></i>
<span slot="title">{{ obj .menuName }}</span>
</template>
</el-menu-item>
</template>
</template>
</div>
</template>
<script>
export default {
name:'MenuList',
props: {
objList: Array,
},
}
</script>
<style scoped>
</style>
2. 引用自定义组件
import MenuList from '../components/MenuList' //先引用vue文件
export default{
components:{ //添加组件
MenuList
},
data(){
}
.....
}
3. 使用自定义组件
<el-menu
unique-opened
:collapse="isCollapse"
router>
<menu-list :objList="menuList" ></menu-list>
</el-menu>
OK完工。以上就是Vue实现动态菜单+动态路由(基于elementUI)的全部内容,如果还有其他不懂的可以添加右下角微信,欢迎骚扰!
大家也可以点击我的gitee来获取我的其他项目源码。 拜拜!