学习springboot+vue笔记十五--动态菜单及动态路由

接之前的文件架构。
这次动态菜单和动态路由主要涉及到前端。

动态菜单实现

在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页面。
测试成功!!

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cngm110

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值