< elementUi 中 封装 NavMenu 导航菜单,实现单页面侧边导航栏 >


👉 前言

在 Vue + elementUi 开发中,在大部分后台管理系统都会选择实现 “ 单页面 ” 应用,简称:SPA。但是实现单页面应用,页面布局显然很重要,在开发中,有时候需要,自己编写一个 单页面导航栏。本篇文章将简单展示! 案例仅供参考!

💡 Tips: 虽然现如今,有着许多可以开箱即用的后台管理系统框架,如: vue-admin、Vue element admin、PigX、Antd Pro Vue等等。但是俗话说的好: “ 打铁还需自身硬 ”, 所以给需要自定义 单页面导航栏的小伙伴展示案例,希望能有所帮助!

👉 一、原理

运用 v-for 循环遍历给定的参数,按照指定参数渲染对应的 侧边导航栏。原理较为简单,直接上案例即可。

使用到 elementUi 的 NavMenu 导航菜单组件 ,点击了解详细使用规则!

👉 二、实现案例

> HTML模板

<template>
  <div :class="$root.themeHomeChange === '1' ? 'riskControlCenter_light' : 'riskControlCenter'">
    <div class="left">
      <el-menu :default-active="$route.query.index"
               class="el-menu-vertical"
               :text-color="$root.themeHomeChange === '1' ? '#adadad' : '#64b6fa'"
               @select="handleSelect"
               :collapse="isCollapse"
               unique-opened>
        <div v-for="item in menuList" :key="item.index">
          <el-menu-item v-if="item.children.length === 0" :index="item.index">
            <i :class="item.icon"></i>
            <span slot="title">{{item.title}}</span>
          </el-menu-item>
          <el-submenu v-else :index="item.index">
            <template slot="title">
              <i :class="item.icon"></i>
              <span v-show="!isCollapse" slot="title">{{item.title}}</span>
            </template>
            <el-menu-item-group>
              <div v-for="item1 in item.children" :key="item1.index">
                <el-menu-item v-if="item1.children.length === 0" :index="item1.index">
                  <i :class="item1.icon"></i>
                  <span slot="title">{{item1.title}}</span>
                </el-menu-item>
                <el-submenu v-else :index="item1.index">
                  <template slot="title">
                    <i :class="item1.icon"></i>
                    <span v-show="!isCollapse" slot="title">{{item1.title}}</span>
                  </template>
                  <el-menu-item-group>
                    <div v-for="item2 in item1.children" :key="item2.index">
                      <el-menu-item v-if="item2.children.length === 0" :index="item2.index">
                        <i :class="item2.icon"></i>
                        <span slot="title">{{item2.title}}</span>
                      </el-menu-item>
                      <el-submenu v-else :index="item2.index">
                        <template slot="title">
                          <i :class="item2.icon"></i>
                          <span v-show="!isCollapse" slot="title">{{item2.title}}</span>
                        </template>
                        <el-menu-item-group>
                          <div v-for="item3 in item2.children" :key="item3.index">
                            <el-menu-item v-if="item3.children.length === 0" :index="item3.index">
                              <i :class="item3.icon"></i>
                              <span slot="title">{{item3.title}}</span>
                            </el-menu-item>
                          </div>
                        </el-menu-item-group>
                      </el-submenu>
                    </div>
                  </el-menu-item-group>
                </el-submenu>
              </div>
            </el-menu-item-group>
          </el-submenu>
        </div>
      </el-menu>
      <el-button :icon="isCollapse ? 'el-icon-d-arrow-right' : 'el-icon-d-arrow-left'"
                 class="btnGroup"
                 @click="() => { isCollapse = !isCollapse; $forceUpdate() }"
                 type="primary"
      ></el-button>
    </div>
    
    <div
      class="right"
      :style="{
        'background': $root.themeHomeChange === '1' ? '#eef3ff' : '#05163d'
      }"
      ref="riskControlCenter">
      <!-- <router-view ></router-view> -->
    </div>
  </div>
    
</template>

<script>
  export default {
    name: "riskControlCenter",
    data(){
      return {
        isCollapse : true,
        routerList: {},
        menuList: [
          {
            title: '总览',
            path: '/overView',
            index: '3-1',
            icon: 'el-icon-data-line',
            children: []
          },
          {
            title: '合规任务',
            path: '/overManage',
            index: '3-2',
            icon: 'el-icon-setting',
            children: []
          },
          {
            title: '防火墙',
            path: '/firewall',
            index: '3-3',
            icon: 'el-icon-film',
            children: [
              {
                title: '防火墙规则监测',
                path: '/firewallRuleMonitor',
                index: '3-3-1',
                icon: 'el-icon-set-up',
                children: []
              },
            ]
          }
    },
    mounted() {},
    created() {
      this.setRouterList(this.menuList);
      if(this.$route.path === '/riskControlCenter') {
        this.init(this.$route.query.index);
      }
    },
    watch: {
      $route(v) {
        if(v.path === '/riskControlCenter') {
          this.init(this.$route.query.index);
        }
      }
    },
    methods: {
      init(index) {
        index = index ? index : '3-1';
        this.setRouterList(this.menuList);
        this.$router.push({
          path: this.routerList[index],
          query: {
            ...this.$route.query,
            index: index,
            actNav: this.$route.query.actNav
          }
        });
      },
      // 设置回调函数,取出树状数据中的所需数据,扁平化,减少后续循环
      setRouterList(data) {
        data.forEach(item => {
          if(item.children.length === 0) {
            this.routerList[item.index] = item.path;
          } else {
            this.setRouterList(item.children);
          }
        })
      },
      handleSelect(key) {
        // console.log(key, keyPath, this.routerList[key]);
        // 获取设置的路由地址
        this.$router.push({
          path: this.routerList[key],
          query: {
            index: key,
            actNav: this.$route.query.actNav
          }
        });
      }
    }
  }
</script>

<style scoped lang="scss">
  .riskControlCenter_light {
    height: 100%;
    display: flex;
    justify-content: space-between;
    /deep/ .el-menu {
      background: #fff;
      border: none;
      .el-menu-item:not(.is-active), .el-submenu__title:not(.is-active) {
        i {
          color: #4389f9;
        }
        &:hover {
          color: #4389f9;
          background: rgba($color: #4389f9, $alpha: .3);
        }
      }
      .el-menu-item.is-active {
        color: #fff;
        background: #4389f9;
      }
    }
    .left {
      width: auto;
      height: 100%;
      background: #fff;
      position: relative;
      .el-menu-vertical:not(.el-menu--collapse) {
        min-width: 150px;
        font-size: 14px;
        font-weight: bold;
      }
      .btnGroup {
        position: absolute;
        z-index: 999;
        width: 25px;
        border-radius: 0 5px 5px 0;
        padding: 14px 4px;
        right: -25px;
        top: 50%;
      }
    }
  
    .right{
      width: 100%;
      overflow-y: auto;
      background: #eef3ff;
    }
  }
  .riskControlCenter {
    height: 100%;
    display: flex;
    justify-content: space-between;
    /deep/ .el-menu, .el-menu .el-menu--popup {
      background: #1a3066;
      border: none;
      .el-menu-item, .el-submenu__title {
        &:hover {
          color: #fff;
          background: #4389f9;
        }
      }
      .el-menu-item.is-active, .el-submenu__title.is-active {
        color: #fff;
        background: #4389f9;
      }
    }
    .left {
      width: auto;
      height: 100%;
      background: #1a3066;
      position: relative;
      .el-menu-vertical:not(.el-menu--collapse) {
        min-width: 150px;
        font-size: 14px;
        font-weight: bold;
      }
      .btnGroup {
        position: absolute;
        z-index: 999;
        width: 25px;
        border-radius: 0 5px 5px 0;
        padding: 14px 4px;
        right: -25px;
        top: 50%;
      }
    }

    .right{
      width: 100%;
      overflow-y: auto;
      background: #05163d;
    }
  }
</style>

案例较为粗浅,仅供参考! 其实可以再对其简化,使用循环嵌套,在Vue指令上,添加Js逻辑判断(三元运算),减少HTML结构庸余。

👉 后续补充

自定义导航栏收起后,鼠标悬浮提示栏样式
样式效果
HTML代码
需要在所需自定义样式的下拉<el-submenu> 中设置 popper-class 属性。

<el-submenu
	:popper-class="$root.themeHomeChange === '1' ? 'submenu_diy_light' : 'submenu_diy'"
	v-else
	:index="item2.index"
	:disabled="item2.disabled"
>...</el-submenu>

CSS代码

<style lang="scss">
// 浅色系
.submenu_diy_light {
  background: #fff;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 5%);
  padding: 10px;
  margin-left: 30px;
  &::after {
    content: "";
    display: block;
    width: 15px;   
    height: 15px;
    background: #fff;
    position: absolute;
    top: 25%;
    left: -7.5px;
    transform: rotate(-45deg);
  }
  .el-menu {
    box-shadow: none;
    .el-menu-item-group__title {
      display: none;
    }
  }
}
// 深色系
.submenu_diy {
  background: #1A2B53;
  box-shadow: 0 10px 20px 0 rgba(0, 0, 0, 50%);
  padding: 10px;
  margin-left: 30px;
  &::after {
    content: "";
    display: block;
    width: 15px;   
    height: 15px;
    background: #1A2B53;
    position: absolute;
    top: 15%;
    left: -7.5px;
    transform: rotate(-45deg);
  }
  .el-menu {
    background: #1A2B53;
    box-shadow: none;
    color: #fff!important;
    .el-menu-item-group__title {
      display: none;
    }
    .el-menu-item {
      span {
        color: #fff;
        font-weight: bold;
      }
      &:hover {
        background: #1a4177;
      }
    }
    .el-menu-item.is-active {
       background: #1a4177;
    }
  }
}
</style>

👉 三、效果演示

效果演示


往期内容 💨

🔥 < 了解 HTTP 这一篇就够了 :什么是 HTTP ?HTTP 和 HTTPS 有什么区别 ? >

🔥 < 每日小技巧:Vue常用修饰符 >

🔥 <Javascript技巧: Javascript 是个难泡的妞,学点技巧征服 “ 她 ” >

🔥 < 谈谈对 SPA(单页面应用)的理解 >

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

技术宅小温

你小小的鼓励,是我搬砖的动力!

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

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

打赏作者

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

抵扣说明:

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

余额充值