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

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

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="/"><img src="../../assets/logo.png" style="padding-left:8px;"></a>
</div>
<div class="topbar-logos">
<a href="/" 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+命名视图实现复杂顶部和左侧导航栏的更多相关文章

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

    描述:如图 项目路径如下图所示: 代码实现: 首先在store.js中添加两个状态: import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vue ...

  2. iOS开发笔记13:顶部标签式导航栏及下拉分类菜单

    当内容及分类较多时,往往采用顶部标签式导航栏,例如网易新闻客户端的顶部分类导航,最近刚好有这样的应用场景,参考网络上一些demo,实现了这种导航效果,记录一些要点. 效果图(由于视频转GIF掉帧,滑动 ...

  3. React Native(四)——顶部以及底部导航栏实现方式

    效果图: 一步一步慢慢来: 其实刚入手做app的时候,就应该做出简单的顶部以及底部导航栏.无奈又在忙其他事情,导致这些现在才整理出来. 1.顶部导航栏:react-native-scrollable- ...

  4. dedecms左侧导航栏不显示问题

    dedecms左侧导航栏不显示问题 在做织梦项目时,经常会碰到后台左侧导航栏不显示的问题,如下所示: ​ 这主要是由于文件权限不足造成的.有两种方法 第一种:把 /data 文件夹全部改成 777 权 ...

  5. CI框架后台添加左侧导航栏出现的一系列问题

  6. MFC office2007风格设置左侧导航栏 [转]

    当基础的框架搭好以后,我想为其添加一个左侧导航栏,过程如下:在框架类的头文件添加一个导航栏参数: CMFCOutlookBar m_navigation; 为了完善功能,在导航栏里面我添加了一个CTr ...

  7. 修改layui的后台模板的左侧导航栏可以伸缩

    原生的左侧导航栏代码: <div class="layui-side layui-bg-black"> <div class="layui-side-s ...

  8. 简单的jquery左侧导航栏和页面选中效果

    这里是要实现导航的左侧并选中的,此功能需引用jquery 效果: 左侧导航 <div class="box"> <ul class="menu" ...

  9. 前端(各种demo)二:左侧导航栏的折叠和打开(不使用js)基础版和升级版

    1.给div设置定位. 复习一下—— css中position有五种属性: static:默认值,没有定位 absolute:绝对定位,相对于父级元素进行定位 relative:相对定位 fixed: ...

随机推荐

  1. [原][OE][官方例子]osgearth_features OE地球添加shp文件(特征标识)

    OE所有官方样例 官方示例代码 /* -*-c++-*- */ /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph * Co ...

  2. shell编程系列10--文本处理三剑客之sed利用sed查询特定内容

    shell编程系列10--文本处理三剑客之sed利用sed查询特定内容 利用sed查找文件内容: pattern种类: .8p .,10p .,+5p ./regexp/p .,/regexp/p . ...

  3. ISO/IEC 9899:2011 条款6.5.16——赋值操作符

    6.5.16 赋值操作符 语法 1.assignment-expression: conditional-expression unary-expression    assignment-opera ...

  4. matlab基本函数randperm end数组索引

    一起来学演化计算-matlab基本函数randperm end数组索引 觉得有用的话,欢迎一起讨论相互学习~Follow Me 随机排列 语法 p = randperm(n) p = randperm ...

  5. PAT 甲级 1144 The Missing Number (20 分)(简单,最后一个测试点没过由于开的数组没必要大于N)

    1144 The Missing Number (20 分)   Given N integers, you are supposed to find the smallest positive in ...

  6. PAT 甲级 1068 Find More Coins (30 分) (dp,01背包问题记录最佳选择方案)***

    1068 Find More Coins (30 分)   Eva loves to collect coins from all over the universe, including some ...

  7. dubbo+zookeeper+springboot简单示例

    目录 dubbo+zookeeper+springboot简单示例 zookeeper安装使用 api子模块 生产者producer 消费者consumer @(目录) dubbo+zookeeper ...

  8. (NSNumber **)value和(NSNumber * __autoreleasing *)value

    今天在看别人开源项目的时候看到这样的代码: 正文从这里开始~~~ 定义如下: /** 评论详情页基础设置 @param BaseSettingBlock 基础设置 */ - (void)setUpCo ...

  9. DALFactory出现"未能加载文件或程序集“DAL”或它的某一个依赖项。系统找不到指定的文件”的解决方案 .

    自己在使用抽象工厂+配置文件+反射实现重构机房的过程中,遇到了这种情况, 当初自己认真的检查了反射中的代码,都是没有问题,请教了师姐,检查了抽象工厂与反射的使用都没有问题 // 查找我们将要使用的数据 ...

  10. Sublime Text3安装及常用插件安装

    为了使用强大好用的代码编辑器来进行selenium3+Python3的自动化测试. 使用Sublime Text 3非常适合. 1.下载安装 首先到http://www.sublimetext.com ...