在了解了命名视图的用途后,发现用命名视图来实现复杂导航更加省力。更多知识请参考这里

这里只说明重要配置内容,其他内容配置请参考上一篇初始版本:

ElementUI 复杂顶部和左侧导航栏实现

或参考文末提到的github上的项目代码。

项目目录如下:

1、router配置(router/index.js)如下:

import Vue from 'vue'
import Router from 'vue-router'
import TopNav from '@/components/nav/topNav.vue'
import LeftNav from '@/components/nav/leftNav.vue'
import Home from '@/views/home.vue'
import Dashboard from '@/views/workbench/dashboard.vue'
import MySettings from '@/views/workbench/mySettings.vue'
import Mission from '@/views/workbench/mission/mission.vue'
import Plan from '@/views/workbench/plan.vue'
import Maillist from '@/views/workbench/maillist.vue'
import EnterpriseList from '@/views/enterprise/index.vue'
import EnterpriseAdd from '@/views/enterprise/add.vue'
import EnterpriseDetail from '@/views/enterprise/detail.vue'
import EnterpriseValidate from '@/views/enterprise/validate.vue'
import VehicleManage from '@/views/vehicle/index.vue'
import DeptManager from '@/views/dept/index.vue'
Vue.use(Router)

let router = new Router({
  routes: [
    {
      path: '/',
      type: 'home', // 根据type区分不同模块(顶部导航)
      name: 'home', // 根据name区分不同子模块(左侧导航)
      redirect: '/dashboard',
      component: Home,
      children: [
        {
          path: '/dashboard',
          name: '首页', // 当前路由的name(导航栏显示文字)
          components: {
            default: Dashboard,
            top: TopNav,
            aside: LeftNav
          },
          leaf: true, // 只有一个节点
          iconCls: 'iconfont icon-home', // 图标样式class
          menuShow: true
        },
        {
          path: '/mySet',
          components: {
            default: MySettings,
            top: TopNav,
            aside: LeftNav
          },
          name: '我的设置',
          iconCls: 'el-icon-menu',
          menuShow: true,
          children: [
            { path: '/mySet/plan', component: Plan, name: '行程计划', menuShow: true },
            { path: '/mySet/mission', component: Mission, name: '我的任务', menuShow: true },
            { path: '/mySet/maillist', component: Maillist, name: '通讯录', menuShow: true }
          ]
        }
      ]
    },
    {
      path: '/enterpriseManager',
      type: 'enterprise',
      name: 'enterprise',
      component: Home,
      redirect: '/enterprise/list',
      menuShow: true,
      children: [
        {
          path: '/enterprise/list',
          name: '企业信息',
          components: {
            default: EnterpriseList,
            top: TopNav,
            aside: LeftNav
          },
          leaf: true,
          iconCls: 'el-icon-setting',
          menuShow: true
        },
        {
          path: '/enterprise/detail',
          name: '企业详情',
          components: {
            default: EnterpriseDetail,
            top: TopNav,
            aside: LeftNav
          },
          leaf: true,
          iconCls: 'el-icon-setting',
          menuShow: false
        },
        {
          path: '/enterprise/add',
          name: '添加企业',
          components: {
            default: EnterpriseAdd,
            top: TopNav,
            aside: LeftNav
          },
          leaf: true,
          iconCls: 'el-icon-menu',
          menuShow: true
        },
        {
          path: '/enterprise/validate',
          name: '企业认证',
          components: {
            default: EnterpriseValidate,
            top: TopNav,
            aside: LeftNav
          },
          leaf: true,
          iconCls: 'el-icon-menu',
          menuShow: true
        }
      ]
    },
    {
      path: '/vehicleManager',
      type: 'enterprise',
      name: 'vehicle',
      component: Home,
      redirect: '/vehicle/list',
      menuShow: true,
      children: [
        {
          path: '/vehicle/list',
          name: '车辆信息',
          components: {
            default: VehicleManage,
            top: TopNav,
            aside:  LeftNav
          },
          leaf: true, // 只有一个节点
          iconCls: 'iconfont icon-home', // 图标样式class
          menuShow: true
        }
      ]
    },
    {
      path: '/deptManager',
      type: 'enterprise',
      name: 'dept',
      component: Home,
      redirect: '/dept/list',
      menuShow: true,
      children: [
        {
          path: '/dept/list',
          name: '部门信息',
          components: {
            default: DeptManager,
            top: TopNav,
            aside:  LeftNav
          },
          leaf: true, // 只有一个节点
          iconCls: 'iconfont icon-home', // 图标样式class
          menuShow: true
        }
      ]
    }
  ]
});

特别说明:

这里的路由对象router ,设置的是最多三级,一级路由主要对应的是顶部导航和其他无子页面的路由,二级和三级路由分别对应的是左侧导航的一级和二级菜单(比如三级路由对应的就是左侧导航的二级菜单),二级路由设置leaf属性,值为true表明该路由下没有子菜单(如果该路由下的某页面不显示在左侧导航,不算子菜单)。

2、home.vue,这里分别有name=top,aside,default三个视图,top代表顶部导航,aside代表左侧导航,剩下的default就是默认视图,代表右侧内容区

<template>
  <el-row class="container">
    <!--头部-->
    <el-col :span="24"><router-view name="top"></router-view></el-col>
    <el-col :span="24" class="main">
      <!--左侧导航-->
      <router-view name="aside"></router-view>
      <!--右侧内容区-->
      <section class="content-container">
        <div class="grid-content bg-purple-light">
          <el-col :span="24" class="content-wrapper">
            <transition name="fade" mode="out-in">
              <router-view></router-view>
            </transition>
          </el-col>
        </div>
      </section>
    </el-col>
  </el-row>
</template>
<script>
  export default {
    name: 'home',
    data () {
      return {
        loading: false
      }
    }
  }
</script>

3、topNav.vue 是顶部导航菜单的代码

<template>
  <el-row class="container">
    <!--头部-->
    <el-col :span="24" class="topbar-wrap">
      <div class="topbar-logo topbar-btn">
        <a href="/" rel="external nofollow"  rel="external nofollow" ><img src="../../assets/logo.png" style="padding-left:8px;"></a>
      </div>
      <div class="topbar-logos">
        <a href="/" rel="external nofollow"  rel="external nofollow"  style="color: #fff;">车车综合管理</a>
      </div>
      <div class="topbar-title">
        <!-- 注意:这里就是topNavState作用之处,根据当前路由所在根路由的type值判断显示不同顶部导航菜单 -->
        <el-row v-show="$store.state.topNavState==='home'">
          <el-col :span="24">
            <el-menu :default-active="defaultActiveIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect" :router="true">
              <el-menu-item index="/">工作台</el-menu-item>
              <el-menu-item index="/enterpriseManager">企业管理</el-menu-item>
              <el-menu-item index="/orderManager">订单管理</el-menu-item>
              <el-menu-item index="/systemManager">系统管理</el-menu-item>
            </el-menu>
          </el-col>
        </el-row>
        <el-row v-show="$store.state.topNavState==='enterprise'">
          <el-col :span="24">
            <el-menu :default-active="defaultActiveIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect" :router="true">
              <el-menu-item index="/enterpriseManager">企业信息</el-menu-item>
              <el-menu-item index="/vehicleManager">车辆信息</el-menu-item>
              <el-menu-item index="/deptManager">组织架构</el-menu-item>
            </el-menu>
          </el-col>
        </el-row>
      </div>
      <div class="topbar-account topbar-btn">
        <el-dropdown trigger="click">
          <span class="el-dropdown-link userinfo-inner">
            <i class="iconfont icon-user"></i> {{nickname}}   <i class="el-icon-caret-bottom"></i></span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item>
              <div @click="jumpTo('/user/profile')"><span style="color: #555;font-size: 14px;">个人信息</span></div>
            </el-dropdown-item>
            <el-dropdown-item>
              <div @click="jumpTo('/user/changepwd')"><span style="color: #555;font-size: 14px;">修改密码</span></div>
            </el-dropdown-item>
            <el-dropdown-item divided @click.native="logout">退出登录</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </div>
    </el-col>
  </el-row>
</template>
<script>
  import 'element-ui/lib/theme-chalk/display.css';
  import {road} from '../../road.js'

  export default {
    data(){
      return {
        loading: false,
        companyName: '',
        nickname: '',
        defaultActiveIndex: '/',
        homeMenu: false,
        messageCount: 5
      }
    },
    created() {
      road.$on('setNickName', (text) => {
        this.nickname = text;
      });

      road.$on('goto', (url) => {
        if(url === "/login") {
          localStorage.removeItem('access-user');
          this.$router.push(url);
        }
      });
      // 组件创建完后获取数据
      this.fetchNavData();
    },
    methods: {
      jumpTo(url){
        this.$router.push(url); //用go刷新
      },
      handleSelect(index){
        this.defaultActiveIndex = index;
      },
      fetchNavData () { // 初始化菜单激活项
        let cur_path = this.$route.path; //获取当前路由
        let routers = this.$router.options.routes; // 获取路由对象
        let nav_type = "", nav_name = "";
        for (var i = 0; i < routers.length; i  ) {
          let children = routers[i].children;
          if(children){
            for (let j = 0; j < children.length; j  ) {
              if (children[j].path === cur_path) {
                nav_type = routers[i].type;
                nav_name = routers[i].name;
                break;
              }
              // 如果该菜单下还有子菜单
              if(children[j].children) {
                let grandChildren = children[j].children;
                for(let z=0; z<grandChildren.length; z  ) {
                  if(grandChildren[z].path === cur_path) {
                    nav_type = routers[i].type;
                    nav_name = routers[i].name;
                    break;
                  }
                }
              }
            }
          }
        }
        this.$store.state.topNavState = nav_type;
        this.$store.state.leftNavState = nav_name;
        if(nav_type == "home"){
          this.defaultActiveIndex = "/";
        } else {
          this.defaultActiveIndex = "/"   nav_name   "Manager";
        }
      },
      logout(){
        //logout
        this.$confirm('确认退出吗?', '提示', {
          confirmButtonClass: 'el-button--warning'
        }).then(() => {
          //确认
          localStorage.removeItem('access-user');
          road.$emit('goto', '/login');
        }).catch(() => {});
      }
    },
    mounted() {
      let user = window.localStorage.getItem('access-user');
      if (user) {
        user = JSON.parse(user);
        this.nickname = user.nickname || '';
        this.companyName = user.companyName || '';
      }
    },
    watch: {
      '$route': function(to, from){ // 路由改变时执行
        //console.info("to.path:"   to.path);
        this.fetchNavData();
      }
    }
  }
</script>

注意fetchNavData()这个方法,主要是根据当前跳转的路由,去找到这个路由对应的type(对应顶部导航栏的分类)和name(对应左侧导航栏的分类),然后保存type和name到$store中,这样在topNav.vue组件可以根据$store中的type显示相应的菜单,同样在leftNav.vue组件就可以取到这个name值并显示相应的左侧菜单栏了。另外,里面的top和aside是命名视图,分别对应顶部导航组件和左侧导航组件。

补充:topNavState和leftNavState这两个状态就是精髓所在,分别控制顶部和左侧导航展示对应模块菜单,这两个状态是在vuex配置文件store.js中设置的

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const state = {
  collapsed: false, // 左侧导航折叠状态
  topNavState: 'home',
  leftNavState: 'dispatch'
}
export default new Vuex.Store({
  state
})

store.js文件在main.js中引入:

import store from './store.js'
new Vue({
  router,
  store,
  el: '#app',
  render: h => h(App)
})

4、leftNav.vue 左侧导航栏(这里的左侧菜单栏最多有两级菜单)

<template>
  <!--左侧导航-->
  <aside :class="{showSidebar:!collapsed}">
    <!--展开折叠开关-->
    <div class="menu-toggle" @click.prevent="collapse">
      <i class="iconfont icon-outdent" v-show="!collapsed" title="收起"></i>
      <i class="iconfont icon-indent" v-show="collapsed" title="展开"></i>
    </div>
    <!--导航菜单-->
    <el-menu :default-active="$route.path" router :collapse="collapsed" ref="leftNavigation">
      <template v-for="(issue,index) in $router.options.routes">
        <!-- 注意:这里就是leftNavState状态作用之处,当该值与router的根路由的name相等时加载相应菜单组 -->
        <template v-if="issue.name === $store.state.leftNavState">
          <template v-for="(item,index) in issue.children">
            <el-submenu v-if="!item.leaf" :index="index ''" v-show="item.menuShow">
              <template slot="title"><i :class="item.iconCls"></i><span slot="title">{{item.name}}</span></template>
              <el-menu-item v-for="term in item.children" :key="term.path" :index="term.path" v-if="term.menuShow"
                            :class="$route.path==term.path?'is-active':''">
                <i :class="term.iconCls"></i><span slot="title">{{term.name}}</span>
              </el-menu-item>
            </el-submenu>
            <el-menu-item v-else-if="item.leaf" :index="item.path"
                          :class="$route.path==item.path?'is-active':''" v-show="item.menuShow">
              <i :class="item.iconCls"></i><span slot="title">{{item.name}}</span>
            </el-menu-item>
          </template>
        </template>
      </template>
    </el-menu>
  </aside>
</template>
<script>
  export default {
    name: 'leftNav',
    data () {
      return {
        loading: false,
        collapsed: this.$store.state.collapsed,
      }
    },
    methods: {
      //折叠导航栏
      collapse: function () {
        this.collapsed = !this.collapsed;
        this.$store.state.collapsed = this.collapsed;
      },
      // 左侧导航栏根据当前路径默认打开子菜单(如果当前是二级菜单,则父级子菜单默认打开)
      defaultLeftNavOpened () {
        let cur_path = this.$route.path; //获取当前路由
        let routers = this.$router.options.routes; // 获取路由对象
        let subMenuIndex = '', needOpenSubmenu = false;
        for (let i = 0; i < routers.length; i  ) {
          let children = routers[i].children;
          if(children){
            for (let j = 0; j < children.length; j  ) {
              if(children[j].path === cur_path) {
                break;
              }
              // 如果该菜单下还有子菜单
              if(children[j].children && !children[j].leaf) {
                let grandChildren = children[j].children;
                for(let z=0; z<grandChildren.length; z  ) {
                  if(grandChildren[z].path === cur_path) {
                    subMenuIndex = j;
                    needOpenSubmenu = true;
                    break;
                  }
                }
              }
            }
          }
        }
        if(this.$refs['leftNavigation'] && needOpenSubmenu) {
          this.$refs['leftNavigation'].open(subMenuIndex); // 打开子菜单
        }
      },
    },
    watch: {
      '$route': function(to, from){ // 路由改变时执行
        //console.info("to.path:"   to.path);
      }
    },
    mounted() {
      this.defaultLeftNavOpened();
    },
  }
</script>

5、如果左侧导航含有二级菜单,

比如“我的设置(/mySet)”中,含有三个子菜单:

路由配置如下:(具体文件路径及配置请看router/index.js)

{
          path: '/mySet',
          components: {
            default: MySettings,
            top: TopNav,
            aside: LeftNav
          },
          name: '我的设置',
          iconCls: 'el-icon-menu',
          menuShow: true,
          children: [
            { path: '/mySet/plan', component: Plan, name: '行程计划', menuShow: true },
            { path: '/mySet/mission', component: Mission, name: '我的任务', menuShow: true },
            { path: '/mySet/maillist', component: Maillist, name: '通讯录', menuShow: true }
          ]
        }

此时,我们只需在父级菜单对应视图(MySettings)中添加一个router-view即可:

<template>
  <router-view></router-view>
</template>

6、整体效果图:

附上github地址:https://github.com/yqrong/vvproject

到此这篇关于ElementUI 命名视图实现复杂顶部和左侧导航栏的文章就介绍到这了,更多相关Element顶部和左侧导航栏内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

ElementUI+命名视图实现复杂顶部和左侧导航栏的更多相关文章

  1. 使用layui实现左侧菜单栏及动态操作tab项的方法

    这篇文章主要介绍了使用layui实现左侧菜单栏及动态操作tab项的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. 在iOS上绘制扭曲的文本

    使用iOS9及更高版本中提供的标准API,如何在绘制文本时实现扭曲效果?

  3. ios – 如果Element符合给定的协议,则扩展阵列以符合协议

    如果是这样,语法是什么?解决方法Swift4.2在Swift4.2中,我能够使用符合这样的协议的元素扩展数组:

  4. ios – 如何在swift中获取2数组的常见元素列表

    (双关语)编辑:,你可以这样做这个实现是丑陋的.

  5. Swift 函数Count,Filter,Map,Reduce

    Count-统计数量文档示例Filter-条件过滤文档示例-过滤长度大于4的字符串也可以简化Map-映射集合类型,返回数组文档示例同样可以简化Reduce-把数组结合到一起文档示例可以简化进一步简化

  6. Swift语法——Swift Sequences 探究

    今天看到Array的API中有这么一个声明的函数:函数名为extend,所需参数是S类型的newElements,而S首先要实现SequenceType协议。看看APTGeneratorType必须要实现一个函数next(),它的作用就是返回一个Element,注释里说的很清楚:它的作用就是一直返回元素,直到最后。1)Swift调用generate()来生成了一个Generator,这个对象是一个私有的变量即__g;2)__g调用了next()函数,返回了一个optional类型对象element?。这个

  7. Swift 中数组和链表的性能

    尽管如此,我觉得链表的例子非常有意思,而且值得实现和把玩,它有可能会提升数组reduce方法的性能。同时我认为Swift的一些额外特性很有趣:比如它的枚举可以灵活的在对象和具体方法中自由选择,以及“默认安全”。这本书未来的版本可能就会用Swift作为实现语言。拷贝数组消耗的时间是线性的。使用链表还有其他的代价——统计链表节点的个数所需要的时间是统计数组元素个数时间的两倍,因为遍历链表时的间接寻址方式是需要消耗时间的。

  8. Swift中集合类型indexOf(Element)提示错误的解决办法

    简单的竟然出错了!其实看一下错误描述,大概就可以猜到Swift此时不知道你自定义类是如何比较的,如果是Swift内置的各种struct和class就不存在这个问题,比如:解决很简单,添加一个==方法即可:最后补充一下,早期版本的Swift还有一个find函数可以完成类似的功能,但是新版本已经没有该函数了,So你懂的…

  9. swift map reduce 获取下标(index)的方法

    原文:http://stackoverflow.com/questions/28012205/map-or-reduce-with-index-in-swiftYoucanuseenumeratetoconvertasequence(Array,String,etc.)toasequenceoftupleswithanintegercounterandandelementpairedtogethe

  10. Swift中的map 和 flatMap 原理及用法

    map和flatMap是Swift中两个常用的函数,它们体现了Swift中很多的特性。对于简单的使用来说,它们的接口并不复杂,但它们内部的机制还是非常值得研究的,能够帮助我们够好的理解Swift语言。map简介首先,咱们说说map函数如何使用。letnumbers=[1,2,3,4]letresult=numbers.map{$0+2}print//[3,4,5,6]map方法接受一个闭包作为参数,然后它会遍历整个numbers数组,并对数组中每一个元素执行闭包中定义的操作。比如咱们这个例子里面的闭包是讲

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部