总思路:
一、在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