项目需要基于 vue-element-admin 开发,vue-element-admin主要定位是中后台管理系统,而项目又偏向前中台,因此想使用顶部导航栏的方式。原本以为很简单,不就是将 导航栏组件 mode设为 horizontal 就可以了吗,naive~ 排查了一下代码(和官文),发现 :
这里同时也改造了 element-ui 默认侧边栏不少的样式,所有的 css 都可以在 @/styles/sidebar.scss 中找到,你也可以根据自己的需求进行修改。
在收起侧边栏的时候,顶部导航栏样式出现问题(此处无图,大概就是有子目录的节点标题之间的距离没有了)。
不改变导航栏与路由绑定的效果,把侧边栏变成顶部导航栏。
当然也可以同时保留两种方式:
@/styles/sidebar.scss 修改.hideSidebar 的样式
.hideSidebar {
.sidebar-container {
width: 0 !important; //默认54px,收起时会展示图标,因此我们设为0
}
.main-container {
margin-left: 0; //默认54px,收起时会留出 54px 的空白,因此我们设为0
}
.submenu-title-noDropdown {
padding: 0 !important;
position: relative;
.el-tooltip {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
}
}
/* 注释掉.hideSidebar的子样式.el-submenu,避免submenu样式失灵,原因很简单,就是这段代码会导致标题之间距离从原本的20px变成0*/
/* .el-submenu {
overflow: hidden;
&>.el-submenu__title {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
.el-submenu__icon-arrow {
display: none;
}
}
}*/
.el-menu--collapse {
.el-submenu {
&>.el-submenu__title {
&>span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
}
}
}
}
复制一份@/views/layout/Sidebar 组件,粘贴到相同路径下,更改组件名为HeadNavbar
在index.js中声明组件
@/views/layout/HeadNavbar/index.vue 将template修改如下:
<template>
<el-menu
:default-active="activeMenu"
class="el-menu-demo"
mode="horizontal"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu>
</template>
@/views/layout/HeadNavbar/SidebarItem.vue 将template修改如下:
<template>
<!-- style设置为inline-block,避免标题垂直布局-->
<div v-if="!item.hidden" style="display:inline-block;">
<template
v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)">
<item :title="onlyOneChild.meta.title"/>
</el-menu-item>
</app-link>
</template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body >
<template slot="title" >
<item v-if="item.meta" :title="item.meta.title"/>
<!-- 增加固定宽度解决箭头被遮挡的问题-->
<div style="display: inline-block; width:18px;"></div>
</template>
<vertical-item
v-for="child in item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
/>
</el-submenu>
</div>
</template>
@/views/layout/HeadNavbar/VerticalItem.vue 顶部导航栏不需要显示图标,将template修改如下:
<template>
<div v-if="!item.hidden" >
<template
v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)">
<item :title="onlyOneChild.meta.title"/>
</el-menu-item>
</app-link>
</template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title" >
<item v-if="item.meta" :title="item.meta.title"/>
</template>
<vertical-item
v-for="child in item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
/>
</el-submenu>
</div>
</template>
完成以上步骤以后顶部导航栏的组件就改造好了,只需要在index.vue 下引入就可以使用。
<template>
<div>
<div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<sidebar class="sidebar-container"/>
<div :class="{hasTagsView:needTagsView}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar/>
<head-navbar />
<tags-view v-if="needTagsView"/>
</div>
<app-main/>
<right-panel v-if="showSettings">
<settings/>
</right-panel>
</div>
</div>
</div>
</template>
<script>
import RightPanel from '@/components/RightPanel'
import {AppMain, Navbar, Settings, Sidebar, TagsView, HeadNavbar} from './components'
import ResizeMixin from './mixin/ResizeHandler'
import {mapState} from 'vuex'
export default {
name: 'Layout',
components: {
AppMain,
Navbar,
HeadNavbar,
RightPanel,
Settings,
Sidebar,
TagsView
},
~~~~~~~~~~
这里我对Navbar.vue 进行了简单的改造,将relative布局改为flex布局,便于后期加工。附上代码,就不解释了:
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<div class="title">产品全寿命周期服务平台</div>
<!--<breadcrumb id="breadcrumb-container" class="breadcrumb-container" />-->
<div class="right-menu">
<template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
<error-log class="errLog-container right-menu-item hover-effect" />
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="Global Size" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>
</template>
<el-dropdown class="avatar-container right-menu-item hover-effect" 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">
<router-link to="/profile/index">
<el-dropdown-item>Profile</el-dropdown-item>
</router-link>
<router-link to="/">
<el-dropdown-item>Dashboard</el-dropdown-item>
</router-link>
<a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">
<el-dropdown-item>Github</el-dropdown-item>
</a>
<a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
<el-dropdown-item>Docs</el-dropdown-item>
</a>
<el-dropdown-item divided>
<span style="display:block;" @click="logout">Log Out</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'
import ErrorLog from '@/components/ErrorLog'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch'
export default {
components: {
Breadcrumb,
Hamburger,
ErrorLog,
Screenfull,
SizeSelect,
Search
},
computed: {
...mapGetters([
'sidebar',
'avatar',
'device'
])
},
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
async logout() {
await this.$store.dispatch('user/logout')
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
}
}
}
</script>
<style lang="scss" scoped>
.navbar {
height: 100px;
overflow: hidden;
// position: relative;
display: flex;
flex-direction: row;
justify-content:space-between;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
}
.hamburger-container {
line-height: 100px;
height: 100%;
width:50px;
flex:0 0 auto;
float: left;
cursor: pointer;
transition: background .3s;
-webkit-tap-highlight-color:transparent;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
.title{
line-height: 100px;
font-size:40px;
margin-left:20px;
width:500px;
flex:0 0 auto;
}
.breadcrumb-container {
float: left;
}
.errLog-container {
display: inline-block;
vertical-align: top;
}
.right-menu {
flex:1 1 auto;
float: right;
height: 100%;
line-height: 100px;
display:flex;
flex-direction:row;
justify-content: flex-end;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 10px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background .3s;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
}
.avatar-container {
margin-right: 30px;
.avatar-wrapper {
margin-top: 10px;
position: relative;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 10px;
}
.el-icon-caret-bottom {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
</style>