总思路:
一、在layout里加了一个Topbar组件,地址为:src/layout/components/Topbar.vue
Topbar.vue代码如下:
<template>
<div class="top-nav">
<div class="log">一级导航</div>
<el-menu
:active-text-color="variables.menuActiveText"
:default-active="activeMenu"
mode="horizontal"
@select="handleSelect"
>
<div v-for="item in routes" :key="item.path" class="nav-item">
<app-link :to="resolvePath(item)">
<el-menu-item
v-if="!item.hidden"
:index="item.path"
>{{ item.meta ? item.meta.title : item.children[0].meta.title }}</el-menu-item>
</app-link>
</div>
</el-menu>
<div class="right-menu">
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
<i class="el-icon-caret-bottom" />
</div>
<el-dropdown-menu slot="dropdown" class="user-dropdown">
<router-link to="/">
<el-dropdown-item>Home</el-dropdown-item>
</router-link>
<a href="https://github.com/PanJiaChen/vue-admin-template/" target="_blank">
<el-dropdown-item>Github</el-dropdown-item>
</a>
<a href="https://panjiachen.github.io/vue-element-admin-site/#/" target="_blank">
<el-dropdown-item>Docs</el-dropdown-item>
</a>
<el-dropdown-item divided @click.native="logout">
<span style="display:block;">Log Out</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import AppLink from './Sidebar/Link'
import { constantRoutes } from '@/router'
import variables from '@/styles/variables.scss'
import { isExternal } from '@/utils/validate'
export default {
name: 'Topbar',
components: {
AppLink
},
data() {
return {
routes: constantRoutes
}
},
computed: {
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu
}
// 如果是首页,首页高亮
if (path === '/dashboard') {
return '/'
}
// 如果不是首页,高亮一级菜单
const activeMenu = '/' + path.split('/')[1]
return activeMenu
},
variables() {
return variables
},
sidebar() {
return this.$store.state.app.sidebar
},
...mapGetters(['avatar'])
},
mounted() {
this.initCurrentRoutes()
},
methods: {
// 通过当前路径找到二级菜单对应项,存到store,用来渲染左侧菜单
initCurrentRoutes() {
const { path } = this.$route
let route = this.routes.find(
item => item.path === '/' + path.split('/')[1]
)
// 如果找不到这个路由,说明是首页
if (!route) {
route = this.routes.find(item => item.path === '/')
}
this.$store.commit('permission/SET_CURRENT_ROUTES', route)
this.setSidebarHide(route)
},
// 判断该路由是否只有一个子项或者没有子项,如果是,则在一级菜单添加跳转路由
isOnlyOneChild(item) {
if (item.children && item.children.length === 1) {
return true
}
return false
},
resolvePath(item) {
// 如果是个完成的url直接返回
if (isExternal(item.path)) {
return item.path
}
// 如果是首页,就返回重定向路由
if (item.path === '/') {
const path = item.redirect
return path
}
// 如果有子项,默认跳转第一个子项路由
let path = ''
/**
* item 路由子项
* parent 路由父项
*/
const getDefaultPath = (item, parent) => {
// 如果path是个外部链接(不建议),直接返回链接,存在个问题:如果是外部链接点击跳转后当前页内容还是上一个路由内容
if (isExternal(item.path)) {
path = item.path
return
}
// 第一次需要父项路由拼接,所以只是第一个传parent
if (parent) {
path += (parent.path + '/' + item.path)
} else {
path += ('/' + item.path)
}
// 如果还有子项,继续递归
if (item.children) {
getDefaultPath(item.children[0])
}
}
if (item.children) {
getDefaultPath(item.children[0], item)
return path
}
return item.path
},
handleSelect(key, keyPath) {
// 把选中路由的子路由保存store
const route = this.routes.find(item => item.path === key)
this.$store.commit('permission/SET_CURRENT_ROUTES', route)
this.setSidebarHide(route)
},
// 设置侧边栏的显示和隐藏
setSidebarHide(route) {
if (!route.children || route.children.length === 1) {
this.$store.dispatch('app/toggleSideBarHide', true)
} else {
this.$store.dispatch('app/toggleSideBarHide', false)
}
},
async logout() {
await this.$store.dispatch('user/logout')
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
}
}
}
</script>
二、修改src/layout/index.vue
<template>
<div :class="classObj" class="app-wrapper">
<topbar /> <!-- 此处增加topbar-->
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<!-- 侧边栏展示的li列表-->
<sidebar class="sidebar-container" />
<div class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<!-- 导航 -->
<navbar />
</div>
<tags-view /> <!-- 此处增加tag-->
<!-- 主体部分 -->
<app-main />
</div>
</div>
</template>
import { Navbar, Sidebar, AppMain, TagsView ,Topbar } from './components'
components: {
Navbar,
Sidebar,
AppMain,
TagsView,
Topbar
},
.app-wrapper { @include clearfix; position: relative; //height: 100%; height: $contentHeight; 100%; &.mobile.openSidebar{ position: fixed; top: 0; } }
三、修改src/styles/variables.scss
$sideBarWidth: 210px;
$topBarHeight: 56px;
$contentHeight: calc(100vh - 56px);
四、新增src/store/modules/permission.js
import { constantRoutes } from '@/router'
const state = {
routes: [],
addRoutes: [],
currentRoutes: {}
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
},
SET_CURRENT_ROUTES: (state, routes) => {
state.currentRoutes = routes
}
}
export default {
namespaced: true,
state,
mutations
}
五、修改src/store/index.js
import Vue from 'vue' import Vuex from 'vuex' import getters from './getters' import app from './modules/app' import settings from './modules/settings' import user from './modules/user' import tagsView from './modules/tagsView' import permission from './modules/permission' //新增 Vue.use(Vuex) const store = new Vuex.Store({ modules: { app, settings, tagsView, user, permission //新增 }, getters }) export default store
六、
src/store/modules/permission.js