ElementUI?復(fù)雜頂部和左側(cè)導(dǎo)航欄實(shí)現(xiàn)示例
描述:如圖

項(xiàng)目路徑如下圖所示:

代碼實(shí)現(xiàn):
首先在store.js中添加兩個(gè)狀態(tài):
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
topNavState: 'home',
leftNavState: 'home'
}
export default new Vuex.Store({
state
})App.vue內(nèi)容:
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>main.js代碼:
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import store from './store.js'
import 'element-ui/lib/theme-chalk/index.css'
import '@/assets/iconfont.css'
import '@/assets/css/style.css'
Vue.config.productionTip = false
Vue.use(ElementUI)
new Vue({
router,
store,
el: '#app',
render: h => h(App)
})
router/index.js文件聲明路由:
其中:行程計(jì)劃、任務(wù)、通訊錄屬于首頁(yè)大板塊(topNavState=“home”);企業(yè)信息、車輛信息、部門(mén)信息都屬于enterprise這一大板塊(topNavState=“enterprise”)
import Vue from 'vue'
import Router from 'vue-router'
import LeftNav from '@/components/nav/leftNav.vue'
import Home from '@/views/home.vue'
import Dashboard from '@/views/workbench/dashboard.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'
import NotFound from '@/components/404.vue'
// 懶加載方式,當(dāng)路由被訪問(wèn)的時(shí)候才加載對(duì)應(yīng)組件
const Login = resolve => require(['@/views/login'], resolve)
Vue.use(Router)
let router = new Router({
routes: [
{
path: '/login',
type: 'login',
component: Login
},
{
path: '*',
component: NotFound
},
{
path: '/',
type: 'home', // 根據(jù)type區(qū)分不同模塊(頂部導(dǎo)航)
name: 'home', // 根據(jù)name區(qū)分不同子模塊(左側(cè)導(dǎo)航)
redirect: '/dashboard',
component: Home,
menuShow: true,
children: [
{
path: '/dashboard',
component: LeftNav,
name: 'dashboard', // 當(dāng)前路由的name
leaf: true, // 只有一個(gè)節(jié)點(diǎn)
iconCls: 'iconfont icon-home', // 圖標(biāo)樣式class
menuShow: true,
children: [
{ path: '/dashboard', component: Dashboard, name: '首頁(yè)', menuShow: true }
]
},
{
path: '/mySet',
component: LeftNav,
name: '我的設(shè)置',
iconCls: 'el-icon-menu',
menuShow: true,
children: [
{ path: '/mySet/plan', component: Plan, name: '行程計(jì)劃', menuShow: true },
{ path: '/mySet/mission', component: Mission, name: '我的任務(wù)', 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: '/enterpriseList',
component: LeftNav,
name: 'enterpriseList',
leaf: true, // 只有一個(gè)節(jié)點(diǎn)
iconCls: 'iconfont icon-home', // 圖標(biāo)樣式class
menuShow: true,
children: [
{ path: '/enterprise/list', component: EnterpriseList, name: '企業(yè)列表', menuShow: true },
{ path: '/enterprise/detail', component: EnterpriseDetail, name: '企業(yè)詳情', menuShow: false }
]
},
{
path: '/enterpriseAdd',
component: LeftNav,
name: 'enterpriseAdd',
leaf: true, // 只有一個(gè)節(jié)點(diǎn)
iconCls: 'el-icon-menu',
menuShow: true,
children: [
{ path: '/enterprise/add', component: EnterpriseAdd, name: '企業(yè)添加', menuShow: true }
]
},
{
path: '/enterpriseValidate',
component: LeftNav,
name: 'enterpriseValidate',
leaf: true, // 只有一個(gè)節(jié)點(diǎn)
iconCls: 'el-icon-menu',
menuShow: true,
children: [
{ path: '/enterprise/validate', component: EnterpriseValidate, name: '企業(yè)認(rèn)證', menuShow: true }
]
}
]
},
{
path: '/vehicleManager',
type: 'enterprise',
name: 'vehicle',
component: Home,
redirect: '/vehicle/list',
menuShow: true,
children: [
{
path: '/vehicleList',
component: LeftNav,
name: 'vehicleList',
leaf: true, // 只有一個(gè)節(jié)點(diǎn)
iconCls: 'iconfont icon-home', // 圖標(biāo)樣式class
menuShow: true,
children: [
{ path: '/vehicle/list', component: VehicleManage, name: '車輛信息', menuShow: true }
]
}
]
},
{
path: '/deptManager',
type: 'enterprise',
name: 'dept',
component: Home,
redirect: '/dept/list',
menuShow: true,
children: [
{
path: '/deptList',
component: LeftNav,
name: 'deptList',
leaf: true, // 只有一個(gè)節(jié)點(diǎn)
iconCls: 'iconfont icon-home', // 圖標(biāo)樣式class
menuShow: true,
children: [
{ path: '/dept/list', component: DeptManager, name: '部門(mén)信息', menuShow: true }
]
}
]
}
]
});
router.beforeEach((to, from, next) => {
// console.log('to:' + to.path)
if (to.path.startsWith('/login')) {
window.localStorage.removeItem('access-user')
next()
} else if(to.path.startsWith('/register')){
window.localStorage.removeItem('access-user')
next()
} else {
let user = JSON.parse(window.localStorage.getItem('access-user'))
if (!user) {
next({path: '/login'})
} else {
next()
}
}
});
export default router特別說(shuō)明:
這里的路由對(duì)象router ,設(shè)置的是最多三級(jí),一級(jí)路由主要對(duì)應(yīng)的是頂部導(dǎo)航和其他無(wú)子頁(yè)面的路由,二級(jí)和三級(jí)路由分別對(duì)應(yīng)的是左側(cè)導(dǎo)航的一級(jí)和二級(jí)菜單(比如三級(jí)路由對(duì)應(yīng)的就是左側(cè)導(dǎo)航的二級(jí)菜單),二級(jí)路由設(shè)置leaf屬性,值為true表明該路由下沒(méi)有子菜單(如果該路由下的某頁(yè)面不顯示在左側(cè)導(dǎo)航,不算子菜單)。
leftNav.vue文件中主要是左側(cè)導(dǎo)航菜單加載代碼:
<template>
<el-col :span="24" class="main">
<!--左側(cè)導(dǎo)航-->
<aside :class="{showSidebar:!collapsed}">
<!--展開(kāi)折疊開(kāi)關(guān)-->
<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="展開(kāi)"></i>
</div>
<!--導(dǎo)航菜單-->
<el-menu :default-active="$route.path" router :collapse="collapsed" ref="leftNavigation">
<template v-for="(issue,index) in $router.options.routes">
<template v-if="issue.name === $store.state.leftNavState"><!-- 注意:這里就是leftNavState狀態(tài)作用之處,當(dāng)該值與router的根路由的name相等時(shí)加載相應(yīng)菜單組 -->
<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&&item.children&&item.children.length" :index="item.children[0].path"
:class="$route.path==item.children[0].path?'is-active':''" v-show="item.menuShow">
<i :class="item.iconCls"></i><span slot="title">{{item.children[0].name}}</span>
</el-menu-item>
</template>
</template>
</template>
</el-menu>
</aside>
<!--右側(cè)內(nèi)容區(qū)-->
<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>
</template>
<script>
export default {
name: 'leftNav',
data () {
return {
collapsed: false
}
},
methods: {
//折疊導(dǎo)航欄
collapse: function () {
this.collapsed = !this.collapsed;
},
// 左側(cè)導(dǎo)航欄根據(jù)當(dāng)前路徑默認(rèn)打開(kāi)子菜單(如果當(dāng)前路由是三級(jí),則父級(jí)子菜單默認(rèn)打開(kāi))
defaultLeftNavOpened () {
let cur_path = this.$route.path; //獲取當(dāng)前路由
let routers = this.$router.options.routes; // 獲取路由對(duì)象
let subMenuIndex = 0, 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;
}
// 如果該菜單下有子菜單(個(gè)數(shù)>1且設(shè)置的leaf為false才有下拉子菜單)
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); // 打開(kāi)子菜單
}
},
},
mounted() {
this.defaultLeftNavOpened();
}
}
</script>home.vue是后臺(tái)主頁(yè)組件代碼
<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" v-show="!collapsed">
<a href="/" rel="external nofollow" rel="external nofollow" style="color: #fff;">車車綜合管理</a>
</div>
<div class="topbar-title">
<el-row v-show="$store.state.topNavState==='home'"><!-- 注意:這里就是topNavState作用之處,根據(jù)當(dāng)前路由所在根路由的type值判斷顯示不同頂部導(dǎo)航菜單 -->
<el-col :span="24">
<el-menu :default-active="defaultActiveIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect" :router="true">
<el-menu-item index="/">工作臺(tái)</el-menu-item>
<el-menu-item index="/enterpriseManager">企業(yè)管理</el-menu-item>
<el-menu-item index="/orderManager">訂單管理</el-menu-item>
<el-menu-item index="/systemManager">系統(tǒng)管理</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">企業(yè)信息</el-menu-item>
<el-menu-item index="/vehicleManager">車輛信息</el-menu-item>
<el-menu-item index="/deptManager">組織架構(gòu)</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;">個(gè)人信息</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>
<!--中間-->
<transition name="fade" mode="out-in">
<router-view></router-view>
</transition>
</el-row>
</template>
<script>
export default {
name: 'home',
data () {
return {
defaultActiveIndex: "/",
loading: false,
nickname: '',
collapsed: false
}
},
created() {// 組件創(chuàng)建完后獲取數(shù)據(jù),
// 此時(shí) data 已經(jīng)被 observed 了
this.fetchNavData();
},
methods: {
handleSelect(index){
this.defaultActiveIndex = index;
},
//折疊導(dǎo)航欄
collapse () {
this.collapsed = !this.collapsed;
},
fetchNavData () { // 初始化菜單激活項(xiàng)
var cur_path = this.$route.path; //獲取當(dāng)前路由
var routers = this.$router.options.routes; // 獲取路由對(duì)象
var nav_type = "", nav_name = "";
for (var i = 0; i < routers.length; i++) {
var children = routers[i].children;
if(children){
for (var j = 0; j < children.length; j++) {
var grand_children = children[j].children;
if(grand_children){
for (var k = 0; k < grand_children.length; k++) {
if (grand_children[k].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; // 改變topNavState狀態(tài)的值
this.$store.state.leftNavState = nav_name; // 改變leftNavState狀態(tài)的值
if(nav_type == "home"){
this.defaultActiveIndex = "/";
} else {
this.defaultActiveIndex = "/" + nav_name + "Manager";
}
},
jumpTo(url){
this.defaultActiveIndex = url;
this.$router.push(url); //用go刷新
},
logout(){
//logout
let that = this;
this.$confirm('確認(rèn)退出嗎?', '提示', {
confirmButtonClass: 'el-button--warning'
}).then(() => {
//確認(rèn)
localStorage.removeItem('access-user');
that.$router.go('/login'); //用go刷新
}).catch(() => {});
}
},
mounted() {
let user = localStorage.getItem('access-user');
if (user) {
user = JSON.parse(user);
this.nickname = user.nickname || '';
}
},
watch: {
'$route': 'fetchNavData' //監(jiān)聽(tīng)router值改變時(shí),改變導(dǎo)航菜單激活項(xiàng)
}
}
</script>注意fetchNavData()這個(gè)方法,主要是根據(jù)當(dāng)前跳轉(zhuǎn)的路由,去找到這個(gè)路由對(duì)應(yīng)的type(對(duì)應(yīng)頂部導(dǎo)航欄的分類)和name(對(duì)應(yīng)左側(cè)導(dǎo)航欄的分類),然后保存type和name到$store中,這樣在頂部導(dǎo)航可以根據(jù)$store中的type顯示相應(yīng)的菜單,同樣在左側(cè)導(dǎo)航就可以取到這個(gè)name值并顯示相應(yīng)的左側(cè)菜單欄了。
之前寫(xiě)的左側(cè)導(dǎo)航欄(leftNav.vue)的代碼有個(gè)不足的地方——當(dāng)前打開(kāi)頁(yè)面是三級(jí)路由(也就是左側(cè)導(dǎo)航的二級(jí)菜單)時(shí),刷新當(dāng)前頁(yè),(在左側(cè)導(dǎo)航中)當(dāng)前路由所屬的一級(jí)菜單沒(méi)有默認(rèn)打開(kāi)。
解決方案已修改,在leftNav.vue中添加defaultLeftNavOpened()方法,詳情可以回看leftNav.vue的代碼。
對(duì)于這個(gè)項(xiàng)目的demo,也放到了github共享,請(qǐng)看github地址:https://github.com/yqrong/ccproject.git
最近這段時(shí)間把項(xiàng)目修改了下(將頂部導(dǎo)航也提取出來(lái)作為命名視圖),詳情請(qǐng)看下篇:
ElementUI+命名視圖實(shí)現(xiàn)復(fù)雜頂部和左側(cè)導(dǎo)航欄
補(bǔ)充:
今天有位細(xì)心的網(wǎng)友發(fā)現(xiàn)了一個(gè)小問(wèn)題:
左側(cè)導(dǎo)航當(dāng)前激活的是非第一個(gè)菜單時(shí),切換其他頂部導(dǎo)航再切換回來(lái),會(huì)有兩個(gè)激活的菜單。
解決:el-menu標(biāo)簽缺少default-active屬性設(shè)置,加上即可。
<el-menu :default-active="$route.path" router :collapse="collapsed" ref="leftNavigation"> <!-- ... --> </el-menu>
寫(xiě)代碼還是不夠細(xì)心,自我檢討一下。
相關(guān)文章
vue3點(diǎn)擊出現(xiàn)彈窗后背景變暗且不可操作的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue3點(diǎn)擊出現(xiàn)彈窗后背景變暗且不可操作的實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08
富文本編輯器quill.js開(kāi)發(fā)之自定義格式擴(kuò)展
這篇文章主要為大家介紹了富文本編輯器quill.js開(kāi)發(fā)之自定義格式擴(kuò)展,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
簡(jiǎn)單談?wù)刅ue3中的ref和reactive
vue3中實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)的方法是就是使用ref和reactive,所謂響應(yīng)式就是界面和數(shù)據(jù)同步,能實(shí)現(xiàn)實(shí)時(shí)更新,下面這篇文章主要給大家介紹了關(guān)于Vue3中ref和reactive的相關(guān)資料,需要的朋友可以參考下2023-04-04
Vue 監(jiān)聽(tīng)列表item渲染事件方法
今天小編就為大家分享一篇Vue 監(jiān)聽(tīng)列表item渲染事件方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
vue-next/runtime-core 源碼閱讀指南詳解
這篇文章主要介紹了vue-next/runtime-core 源碼閱讀指南詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
vue使用video插件vue-video-player的示例
這篇文章主要介紹了vue使用video插件vue-video-player的示例,幫助大家更好的理解和使用vue插件,感興趣的朋友可以了解下2020-10-10

