赞
踩
接之前的文件架构。
这次动态菜单和动态路由主要涉及到前端。
在aside.vue中修改的e-menu的代码,把之前静态的菜单代码更新为下面的代码
<div > <div v-for="item in menuList" :key="item.id"> <div v-if="item.path"> <el-menu-item :index="item.path" > <i :class="item.icon"></i> {{item.name}}</el-menu-item> </div> <div v-if="!item.path"> <el-submenu :index="item.id+''"> <template slot="title"> <i :class="item.icon"></i> <span slot="title">{{item.name}}</span> </template> <div v-for="subItem in item.children" :key="subItem.id"> <el-menu-item :index="subItem.path"> <i :class="subItem.icon"></i>{{subItem.name}}</el-menu-item> </div> </el-submenu> </div> </div> </div>
之前考虑使用vuex.state保存菜单数据。但刷新后会导致菜单丢失,最后还是使用的localStorage的方案来解决。
data()中增加
return {
menuList:localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")).menuList:null,
ops:[]
}
methods中增加
getOpS(){
const oprarr=this.menuList.filter(item=>item.children.length>0);
this.ops=oprarr.map(item=>{return item.id.toString()})
}
在mountd()中调用方法
this.getOpS()
即可实现绑定的动态菜单效果。
aside.vue的完整代码为:
<template> <div> <el-aside :width="sideWidth +'px'" style="background-color: rgb(238, 241, 246);height:100%" > <el-menu :default-openeds="ops" style="min-height:100%;overflow-x:hidden;width:100%" background-color="rgb(48,65,86)" text-color="#fff" active-text-color="#ffd04b" :collapse-transition="false" :collapse="isCollapse" router > <div style="height:60px;line-height:60px;text-align:center"> <img src="../assets/logo.png" alt="" style="width:20px;position:relative;top:5px;margin-right:5px"> <b style="color:white;" v-show="logotext">后台管理系统</b> </div> <div > <div v-for="item in menuList" :key="item.id"> <div v-if="item.path"> <el-menu-item :index="item.path" > <i :class="item.icon"></i> {{item.name}}</el-menu-item> </div> <div v-if="!item.path"> <el-submenu :index="item.id+''"> <template slot="title"> <i :class="item.icon"></i> <span slot="title">{{item.name}}</span> </template> <div v-for="subItem in item.children" :key="subItem.id"> <el-menu-item :index="subItem.path"> <i :class="subItem.icon"></i>{{subItem.name}}</el-menu-item> </div> </el-submenu> </div> </div> </div> </el-menu> </el-aside> </div> </template> <script> export default { name:'AsidePage', data(){ return { menuList:localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")).menuList:null, ops:[] } } , mounted(){ this.getOpS() } , methods:{ getOpS(){ const oprarr=this.menuList.filter(item=>item.children.length>0); this.ops=oprarr.map(item=>{return item.id.toString()}) } }, computed:{ isCollapse(){ return this.$store.state.isCollapse }, sideWidth(){ return this.$store.state.sideWidth }, logotext(){ return this.$store.state.logotext }, }, } </script> <style> </style>
主要就是动态增加路由,主要涉及到router/index.js的代码修改
把原来一些静态的路由代码修改为
export const setRouters = function(){ const menuList=localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")).menuList:null; if(menuList){ const man_route={path:'/',name:'框架页面',component:()=>import('../view/Main'),redirect:'/home',children:[]}; menuList.forEach(item=>{ if(item.path){ let itemMenu={path:item.path,name:item.name,component:()=>import('../components/'+item.pagePath)}; man_route.children.push(itemMenu); } else if(item.children.length){ item.children.forEach(child=>{ let itemMenu={path:child.path,name:child.name,component:()=>import('../components/'+child.pagePath)}; man_route.children.push(itemMenu); }) } }) router.addRoute(man_route); } }
该段代码要写到加载路由之后,否则会报错。
然后在login.vue登录成功后调用。
handleLog(){
this.Req.post('http://localhost:8181/vueDemo/login',this.user).then(res=>{
if(res.code==200){
this.$router.push("/");
localStorage.setItem("user",res.data!=null?JSON.stringify(res.data):'');
if(this.$router.app==null){
setRouters()
}
}else{
this.$message.error(res.message);
}
})
}
实现动态路由效果。
login.vue的完整代码为:
<template> <div class="wrapper"> <div style="margin:200px auto;background-color:#fff;width:350px;height:300px;padding:20px;border-radius:10px"> <div style="margin:20px 0;text-align:center;font-size:24px" ><b>登 录</b></div> <el-form :model="user" :rules="rules" > <el-form-item prop="username" > <el-input size="medium" style="margin:10px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input> </el-form-item> <!-- <el-input size="medium" style="margin:10px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input> --> <el-form-item prop="password" > <el-input size="medium" style="margin:10px 0" prefix-icon="el-icon-lock" v-model="user.password" show-password @change="handleLog"></el-input> </el-form-item> <div style="margin:10px 0;text-align:right"> <el-button type="primary" size="small" @click="handleLog" >登录 </el-button> <el-button type="waring" size="small" @click="$router.push('/register')">注册 </el-button> </div> </el-form> </div> </div> </template> <script> import { setRouters } from '@/router'; export default { name:'LoginPage', data(){ return{ user:{ username:'', password:'' }, rules:{ username: [ { required: true, message: '请输入用户名', trigger: 'blur' }, { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ], } }}, methods:{ handleLog(){ this.Req.post('http://localhost:8181/vueDemo/login',this.user).then(res=>{ if(res.code==200){ this.$router.push("/"); localStorage.setItem("user",res.data!=null?JSON.stringify(res.data):''); if(this.$router.app==null){ setRouters() } }else{ this.$message.error(res.message); } }) } } } </script> <style scoped="scoped"> .wrapper{ height: 100vh; background-image: linear-gradient(to bottom right,#fc466b ,#3f5efb); overflow: hidden; } </style>
上面的效果可以出来动态路由,不刷新页面的话使用正常,但刷新页面会导致页面丢失。
查询资料,有些提到在路由中判断router.getRoutes()来判断是否存在动态路由的名称来进行是否二次加载setRoutes函数。
但我目前的版本是 “vue-router”: “^3.6.5”,
router.getRoutes返回的是函数不是数据,无法使用上面的解决方案。
解决思路是在router/index.js中的setRouters函数代码之后打印router
console.log(router)
看控制台刷新前后router值的变化,发现里面有一个app的数据刷新后变为null。
所以对上面的解决方案进行修改为判断router.app==null的时候重新加载setRouter。router/idnex.js的完整代码为:
import Vue from 'vue' import VueRouter from 'vue-router' import store from '@/store'; Vue.use(VueRouter) const routes = [ { path: '/login', name: '登录页面', component: ()=>import('../view/Login') }, { path: '/register', name: '注册页面', component: ()=>import ( '../view/RegiPage') }, { path:"/404", name:'404', component:()=>import('../components/NoFind') } ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }); export const setRouters = function(){ const menuList=localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")).menuList:null; if(menuList){ const man_route={path:'/',name:'框架页面',component:()=>import('../view/Main'),redirect:'/home',children:[]}; menuList.forEach(item=>{ if(item.path){ let itemMenu={path:item.path,name:item.name,component:()=>import('../components/'+item.pagePath)}; man_route.children.push(itemMenu); } else if(item.children.length){ item.children.forEach(child=>{ let itemMenu={path:child.path,name:child.name,component:()=>import('../components/'+child.pagePath)}; man_route.children.push(itemMenu); }) } }) router.addRoute(man_route); } } if(router.app==null){ setRouters(); } router.beforeEach((to,from,next)=>{ store.state.currentPathName=to.name; store.commit("setPath"); if(to.matched.length==0){ if(localStorage.getItem("user")){ next("/404"); }else{ next("/login") } } next() }) export default router
另外在header.vue中增加了在logout的时候增加清空路由的代码
handlelogout(){
this.$router.push("/login");
localStorage.removeItem("user");
this.$router.app=null;
},
在路由守卫者增加了判断,如果当前不存在去向路由,则看有没有登录登录,由登录信息意味着没有路由,跳到404页面,没有登录的话则跳到 login页面。
测试成功!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。