当前位置:   article > 正文

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

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

解决动态菜单刷新丢失的问题

之前考虑使用vuex.state保存菜单数据。但刷新后会导致菜单丢失,最后还是使用的localStorage的方案来解决。
data()中增加

return {
        menuList:localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")).menuList:null,
        ops:[]
        }
  • 1
  • 2
  • 3
  • 4

methods中增加

 getOpS(){
        const oprarr=this.menuList.filter(item=>item.children.length>0);
        this.ops=oprarr.map(item=>{return item.id.toString()})
      }
  • 1
  • 2
  • 3
  • 4

在mountd()中调用方法

 this.getOpS()
  • 1

即可实现绑定的动态菜单效果。
在这里插入图片描述

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

动态路由实现

主要就是动态增加路由,主要涉及到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);
   }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

该段代码要写到加载路由之后,否则会报错。
然后在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);
    }
  })
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

实现动态路由效果。
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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

解决刷新后路由丢失的问题

上面的效果可以出来动态路由,不刷新页面的话使用正常,但刷新页面会导致页面丢失。
查询资料,有些提到在路由中判断router.getRoutes()来判断是否存在动态路由的名称来进行是否二次加载setRoutes函数。
但我目前的版本是 “vue-router”: “^3.6.5”,
router.getRoutes返回的是函数不是数据,无法使用上面的解决方案。
解决思路是在router/index.js中的setRouters函数代码之后打印router

console.log(router)
  • 1

看控制台刷新前后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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

另外在header.vue中增加了在logout的时候增加清空路由的代码

 handlelogout(){
         this.$router.push("/login");
         localStorage.removeItem("user"); 
         this.$router.app=null;
      },
  • 1
  • 2
  • 3
  • 4
  • 5

在路由守卫者增加了判断,如果当前不存在去向路由,则看有没有登录登录,由登录信息意味着没有路由,跳到404页面,没有登录的话则跳到 login页面。
测试成功!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/579956
推荐阅读
相关标签
  

闽ICP备14008679号