el-menu无限递归组件完美版本

本文介绍了如何在Vue.js中创建一个无限递归的菜单组件,修复了菜单项和子菜单高亮的问题,以及解决了页面刷新后子菜单仍然保持打开状态的bug。代码示例包括`index.vue`、`router.js`和`menutree.vue`,展示了一个完整的菜单系统,使用Element UI库,并通过监听浏览器URL中的当前路由名称来实现菜单的动态高亮。
摘要由CSDN通过智能技术生成

el-menu无限递归组件完美版本

备注:修复菜单和子菜单高亮问题,及刷新后被点击子菜单依旧打开的bug

效果

在这里插入图片描述

代码

index.vue (递归组件)

<template>
    <div class="proMain">
        <div class="left">
            <menu-sun :menuList="menuList"></menu-sun>
        </div>
        <div class="right">
            <router-view></router-view>
        </div>
    </div>
</template>
<script>
import MenuSun from '../components/menutree.vue'
export default {
    components: {
      MenuSun
    },
    data() {
        return {
            menuList: [
               {
                   name: '一组',
                   id: '1',
                   children: [
                       {
                           name: '子1',
                           id: '1-1'
                       },
                       {
                           name: '子2',
                           id: '1-2'
                       }
                   ]
               },
               {
                   name: '二组',
                   id: '2',
                   children: [
                       {
                           name: '子1',
                           id: '2-1'
                       },
                       {
                           name: '子2',
                           id: '2-2'
                       },
                   ]
               },
               {
                   name: '三组',
                   id: '3'
               },
               {
                   name: '四组',
                   id: '4'
               }
            ]
        }
    },
}
</script>
<style lang="less" scoped>
.proMain {
    height: 1000px;
    display: flex;
    .left {
        flex: 2;
        padding-left: 20px;
        background-color: #fff;
        border-right: 1px solid #ccc;
    }
    .right {
        flex: 10;
        padding-left: 20px;
    }
}
</style>

router.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const originalPush = VueRouter.prototype.push
   VueRouter.prototype.push = function push(location) {
   return originalPush.call(this, location).catch(err => err)
}

const routes = [
  {
    path: '/Home',
    name: 'Home',
    component: Home
  },
  {
    path: '/',
    name: 'Header',
    component: () => import(/* webpackChunkName: "header" */ '../views/header.vue'),
    children: [
      {
          path: '/model/onesetchildone', // 一组子1路由
          name: 'onesetchildone',
          component: () => import(/* webpackChunkName: "onesetchildone" */ '../views/model/onesetchildone.vue')
      },
      {
          path: '/model/onesetchildtwo', // 一组子2路由
          name: 'onesetchildtwo',
          component: () => import(/* webpackChunkName: "onesetchildtwo" */ '../views/model/onesetchildtwo.vue')
      },
      {
          path: '/model/twosetchildone', // 二组子1路由
          name: 'twosetchildone',
          component: () => import(/* webpackChunkName: "twosetchildone" */ '../views/model/twosetchildone.vue')
      },
      {
          path: '/model/twosetchildtwo', // 二组子2路由
          name: 'twosetchildtwo',
          component: () => import(/* webpackChunkName: "twosetchildtwo" */ '../views/model/twosetchildtwo.vue')
      },
      {
          path: '/model/threeset', // 三组路由
          name: 'threeset',
          component: () => import(/* webpackChunkName: "threeset" */ '../views/model/threeset.vue')
      },
      {
          path: '/model/fourset',  // 四组路由
          name: 'fourset',
          component: () => import(/* webpackChunkName: "fourset" */ '../views/model/fourset.vue')
      },
  ]
  }
]

const router = new VueRouter({
  routes
})

export default router

menutree.vue

<template>
  <div>
    <el-menu
      :default-active="currentActive"
      active-text-color="#2b98f7"
      :default-openeds="openeds"
      unique-opened
    >
      <template v-for="(item) in menuList">
        <el-submenu v-if="item.children&&item.children.length>0" :key="item.id" :index="item.id">
          <template slot="title">
            <i v-if="item.id == '1'" class="el-icon-s-help"></i>  <!-- 有子菜单的父菜单前面的图标 -->
            <i v-if="item.id == '2'" class="el-icon-s-custom"></i>
            <span class="sizeTit">{{item.name}}</span>
          </template>
          <menu-sun :menuList="item.children"/> 
        </el-submenu>
        <el-menu-item v-else :key="item.id" :index="item.id" @click="hClick(item)">
            <!-- <img v-if="item.id == '3'"  :src=" bd3 == false ? require(' ../img/a.svg ') : require('../img/a1.svg') " /> 无子菜单的父菜单前面的图标
            <imgv-if="item.id=='4'" :src=" bd4 == false ? require(' ../img/b.svg ') : require('../img/b1.svg') "/> -->
            <span  :class="item.id == '3'||item.id == '4' ? 'sizeTit' : 'childSty'">{{item.name}}</span> <!-- 为无子菜单的父菜单设置样式 -->
        </el-menu-item>
      </template>
    </el-menu>
  </div>
</template>

<script>
import MenuSun from "@/components/menutree.vue";
export default {
    name: "MenuSun",
    components: {
        MenuSun
    },
    props: {
        menuList: {}  // 菜单的数据
    },
    data(){
        return {
            currentActive: '',
            bd3: false,
            bd4: false,
            pathMap: {   // 路由名映射菜单id   都是子菜单和无子菜单
                'onesetchildone': '1-1',
                'onesetchildtwo': '1-2',
                'twosetchildone': '2-1',
                'twosetchildtwo': '2-2',
                'threeset': '3',
                'fourset': '4'
            },
        }
    },
    computed: {
        ativePath(){
            let v = this.$route.name
            if(v == 'threeset') {
                 this.bd3 = true
             } else {
                this.bd3 = false
             }
             if(v == 'fourset') {
                 this.bd4 = true
             } else {
                this.bd4 = false
             }
            return v
        },
        openeds(){  // 设置刷新被点击子菜单的父菜单展开
           var name = this.$route.name
           var arr1 = ['onesetchildone', 'onesetchildtwo']  // 第一个父菜单下所有子路由名
           var arr2 = ['twosetchildone', 'twosetchildtwo']  // 第二个父菜单下所有子路由名
           // 浏览器url路由名在哪个数组,该父菜单就会打开
           if(arr1.indexOf(name) != -1){
               return ['1']
            } else if (arr2.indexOf(name) != -1){
               return ['2']
           } else {
               return []
           }
        }
    },
    watch:{
        ativePath(v){
            this.currentActive = this.pathMap[v]
            if(v == 'threeset') {
                 this.bd3 = true
             } else {
                this.bd3 = false
             }
             if(v == 'fourset') {
                 this.bd4 = true
             } else {
                this.bd4 = false
             }
        }
    },
    mounted(){
        var name = this.$route.name
        this.currentActive = this.pathMap[name]
    },
    methods: {
        hClick(i){  // 点击无子菜单的菜单或子菜单
           if(i.id == '1-1'){
               this.$router.push({name: 'onesetchildone'})
           } else if (i.id == '1-2'){
               this.$router.push({name: 'onesetchildtwo'})
           } else if (i.id == '2-1'){
               this.$router.push({name: 'twosetchildone'})
           } else if (i.id == '2-2'){
               this.$router.push({name: 'twosetchildtwo'})
           } else if (i.id == '3'){
               this.$router.push({name: 'threeset'})
           } else if (i.id == '4'){
               this.$router.push({name: 'fourset'})
           }      
        }
    }
};
</script>
<style lang="less" scoped>
.sizeTit {
    font-size: 18px;
    font-weight: 700;
}
.childSty{
    padding-left: 28px;  // 子菜单缩进
}
</style>

上面代码18-22行使用的是ui切的svg,下面代码这几行是使用elementui的图标
在这里插入图片描述

总结:拿到浏览器url里的当前路由名字,监听,让这个名字和菜单id做映射,成功的就高亮

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值