refactor:router&&sidemenu
This commit is contained in:
parent
29ec7f8a18
commit
86096e4eab
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
|
||||
<router-link v-if='item.redirect==="noredirect"||index==levelList.length-1' to="" class="no-redirect">{{item.name}}</router-link>
|
||||
<router-link v-else :to="item.redirect||item.path">{{item.name}}</router-link>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path" v-if='item.meta.title'>
|
||||
<span v-if='item.redirect==="noredirect"||index==levelList.length-1' class="no-redirect">{{item.meta.title}}</span>
|
||||
<router-link v-else :to="item.redirect||item.path">{{item.meta.title}}</router-link>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
|
@ -23,8 +23,8 @@ export default {
|
|||
getBreadcrumb() {
|
||||
let matched = this.$route.matched.filter(item => item.name)
|
||||
const first = matched[0]
|
||||
if (first && (first.name !== 'Home' || first.path !== '')) {
|
||||
matched = [{ name: 'Home', path: '/' }].concat(matched)
|
||||
if (first && first.name !== 'dashboard') {
|
||||
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
|
||||
}
|
||||
this.levelList = matched
|
||||
}
|
||||
|
@ -38,14 +38,14 @@ export default {
|
|||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 10px;
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 10px;
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<template>
|
||||
<div class='scroll-container' ref='scrollContainer' @mousewheel="handleScroll">
|
||||
<div class='scroll-wrapper' ref='scrollWrapper' :style="{top: top + 'px'}">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const delta = 15
|
||||
export default {
|
||||
name: 'scrollBar',
|
||||
data() {
|
||||
return {
|
||||
top: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleScroll(e) {
|
||||
e.preventDefault()
|
||||
const $container = this.$refs.scrollContainer
|
||||
const $containerHeight = $container.offsetHeight
|
||||
const $wrapper = this.$refs.scrollWrapper
|
||||
const $wrapperHeight = $wrapper.offsetHeight
|
||||
if (e.wheelDelta > 0) {
|
||||
this.top = Math.min(0, this.top + e.wheelDelta)
|
||||
} else {
|
||||
if ($containerHeight - delta < $wrapperHeight) {
|
||||
if (this.top < -($wrapperHeight - $containerHeight + delta)) {
|
||||
this.top = this.top
|
||||
} else {
|
||||
this.top = Math.max(this.top + e.wheelDelta, $containerHeight - $wrapperHeight - delta)
|
||||
}
|
||||
} else {
|
||||
this.top = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
@import '../../styles/variables.scss';
|
||||
|
||||
.scroll-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: $menuBg;
|
||||
.scroll-wrapper {
|
||||
position: absolute;
|
||||
width: 100%!important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,19 +1,23 @@
|
|||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
const _import = require('./_import_' + process.env.NODE_ENV)
|
||||
// in development env not use Lazy Loading,because Lazy Loading too many pages will cause webpack hot update too slow.so only in production use Lazy Loading
|
||||
|
||||
/* layout */
|
||||
import Layout from '../views/layout/Layout'
|
||||
// in development-env not use lazy-loading, because lazy-loading too many pages will cause webpack hot update too slow. so only in production use lazy-loading;
|
||||
// detail: https://panjiachen.github.io/vue-element-admin-site/#/lazy-loading
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
/* Layout */
|
||||
import Layout from '../views/layout/Layout'
|
||||
|
||||
/**
|
||||
* icon : the icon show in the sidebar
|
||||
* hidden : if `hidden:true` will not show in the sidebar
|
||||
* redirect : if `redirect:noredirect` will not redirct in the levelbar
|
||||
* noDropdown : if `noDropdown:true` will not has submenu in the sidebar
|
||||
* meta : `{ role: ['admin'] }` will control the page role
|
||||
* hidden: true if `hidden:true` will not show in the sidebar(default is false)
|
||||
* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
|
||||
* name:'router-name' the name is used by <keep-alive> (must set!!!)
|
||||
* meta : {
|
||||
role: ['admin','editor'] will control the page role (you can set multiple roles)
|
||||
title: 'title' the name show in submenu and breadcrumb (recommend set)
|
||||
icon: 'svg-name' the icon show in the sidebar,
|
||||
}
|
||||
**/
|
||||
export const constantRouterMap = [
|
||||
{ path: '/login', component: _import('login/index'), hidden: true },
|
||||
|
@ -24,7 +28,11 @@ export const constantRouterMap = [
|
|||
redirect: '/dashboard',
|
||||
name: 'Dashboard',
|
||||
hidden: true,
|
||||
children: [{ path: 'dashboard', component: _import('dashboard/index') }]
|
||||
children: [{
|
||||
path: 'dashboard',
|
||||
component: _import('dashboard/index'),
|
||||
meta: { title: 'dashboard', icon: 'dashboard' }
|
||||
}]
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -32,9 +40,14 @@ export const constantRouterMap = [
|
|||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
name: 'Example',
|
||||
icon: 'example',
|
||||
meta: { title: 'Example', icon: 'example' },
|
||||
children: [
|
||||
{ path: 'index', name: 'Form', icon: 'form', component: _import('page/form') }
|
||||
{
|
||||
path: 'index',
|
||||
name: 'Form',
|
||||
component: _import('page/form'),
|
||||
meta: { title: 'Form', icon: 'form' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -42,9 +55,12 @@ export const constantRouterMap = [
|
|||
path: '/table',
|
||||
component: Layout,
|
||||
redirect: '/table/index',
|
||||
icon: 'table',
|
||||
noDropdown: true,
|
||||
children: [{ path: 'index', name: 'Table', component: _import('table/index'), meta: { role: ['admin'] }}]
|
||||
children: [{
|
||||
path: 'index',
|
||||
name: 'Table',
|
||||
component: _import('table/index'),
|
||||
meta: { title: 'Table', icon: 'table', role: ['admin'] }}
|
||||
]
|
||||
},
|
||||
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
@import './element-ui.scss';
|
||||
@import './variables.scss';
|
||||
@import './mixin.scss';
|
||||
@import './transition.scss';
|
||||
@import './element-ui.scss';
|
||||
@import './sidebar.scss';
|
||||
|
||||
body {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
#app {
|
||||
// 主体区域
|
||||
.main-container {
|
||||
min-height: 100%;
|
||||
transition: margin-left 0.28s;
|
||||
margin-left: 180px;
|
||||
} // 侧边栏
|
||||
.sidebar-container {
|
||||
transition: width 0.28s;
|
||||
width: 180px!important;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
a {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
.svg-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
.el-menu {
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.hideSidebar {
|
||||
.sidebar-container,.sidebar-container .el-menu {
|
||||
width: 36px!important;
|
||||
// overflow: inherit;
|
||||
}
|
||||
.main-container {
|
||||
margin-left: 36px;
|
||||
}
|
||||
}
|
||||
.hideSidebar {
|
||||
.submenu-title-noDropdown {
|
||||
padding-left: 10px!important;
|
||||
position: relative;
|
||||
span {
|
||||
height: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
transition: opacity .3s cubic-bezier(.55, 0, .1, 1);
|
||||
opacity: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
&:hover {
|
||||
span {
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
z-index: 1002;
|
||||
width: 140px;
|
||||
height: 56px;
|
||||
visibility: visible;
|
||||
position: absolute;
|
||||
right: -145px;
|
||||
text-align: left;
|
||||
text-indent: 20px;
|
||||
top: 0px;
|
||||
background-color: $subMenuBg!important;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-submenu {
|
||||
&>.el-submenu__title {
|
||||
padding-left: 10px!important;
|
||||
&>span {
|
||||
display: none;
|
||||
}
|
||||
.el-submenu__icon-arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.nest-menu {
|
||||
.el-submenu__icon-arrow {
|
||||
display: block!important;
|
||||
}
|
||||
span {
|
||||
display: inline-block!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.nest-menu .el-submenu>.el-submenu__title,
|
||||
.el-submenu .el-menu-item {
|
||||
min-width: 180px!important;
|
||||
background-color: $subMenuBg!important;
|
||||
&:hover {
|
||||
background-color: $menuHover!important;
|
||||
}
|
||||
}
|
||||
.el-menu--collapse .el-menu .el-submenu{
|
||||
min-width: 180px!important;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
//sidebar
|
||||
$menuBg:#304156;
|
||||
$subMenuBg:#1f2d3d;
|
||||
$menuHover:#001528;
|
|
@ -1,8 +1,6 @@
|
|||
<template>
|
||||
<div class="app-wrapper" :class="{hideSidebar:!sidebar.opened}">
|
||||
<div class="sidebar-wrapper">
|
||||
<sidebar class="sidebar-container"></sidebar>
|
||||
</div>
|
||||
<sidebar class="sidebar-container"></sidebar>
|
||||
<div class="main-container">
|
||||
<navbar></navbar>
|
||||
<app-main></app-main>
|
||||
|
@ -10,7 +8,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { Navbar, Sidebar, AppMain } from '@/views/layout/components'
|
||||
|
||||
|
@ -30,52 +27,11 @@ export default {
|
|||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
@import "src/styles/mixin.scss";
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
&.hideSidebar {
|
||||
.sidebar-wrapper {
|
||||
transform: translate(-140px, 0);
|
||||
.sidebar-container {
|
||||
transform: translate(132px, 0);
|
||||
}
|
||||
&:hover {
|
||||
transform: translate(0, 0);
|
||||
.sidebar-container {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
.main-container {
|
||||
margin-left: 40px;
|
||||
}
|
||||
}
|
||||
.sidebar-wrapper {
|
||||
width: 180px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
overflow: hidden;
|
||||
transition: all .28s ease-out;
|
||||
}
|
||||
.sidebar-container {
|
||||
transition: all .28s ease-out;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: -17px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.main-container {
|
||||
min-height: 100%;
|
||||
transition: all .28s ease-out;
|
||||
margin-left: 180px;
|
||||
}
|
||||
}
|
||||
@import "src/styles/mixin.scss";
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -51,49 +51,44 @@ export default {
|
|||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
border-radius: 0px !important;
|
||||
.hamburger-container {
|
||||
line-height: 58px;
|
||||
height: 50px;
|
||||
float: left;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.errLog-container {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 150px;
|
||||
}
|
||||
.screenfull {
|
||||
position: absolute;
|
||||
right: 90px;
|
||||
top: 16px;
|
||||
color: red;
|
||||
}
|
||||
.avatar-container {
|
||||
height: 50px;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 35px;
|
||||
.avatar-wrapper {
|
||||
cursor: pointer;
|
||||
margin-top: 5px;
|
||||
position: relative;
|
||||
.user-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.el-icon-caret-bottom {
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
top: 25px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.navbar {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
border-radius: 0px !important;
|
||||
.hamburger-container {
|
||||
line-height: 58px;
|
||||
height: 50px;
|
||||
float: left;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.screenfull {
|
||||
position: absolute;
|
||||
right: 90px;
|
||||
top: 16px;
|
||||
color: red;
|
||||
}
|
||||
.avatar-container {
|
||||
height: 50px;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 35px;
|
||||
.avatar-wrapper {
|
||||
cursor: pointer;
|
||||
margin-top: 5px;
|
||||
position: relative;
|
||||
.user-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.el-icon-caret-bottom {
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
top: 25px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
@ -1,24 +1,32 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class='menu-wrapper'>
|
||||
<template v-for="item in routes">
|
||||
<router-link v-if="!item.hidden&&item.noDropdown&&item.children.length>0" :to="item.path+'/'+item.children[0].path">
|
||||
<el-menu-item :index="item.path+'/'+item.children[0].path">
|
||||
<svg-icon v-if='item.icon' :icon-class="item.icon" /> {{item.children[0].name}}
|
||||
|
||||
<router-link v-if="!item.hidden&&item.children&&item.children.length===1" :to="item.path+'/'+item.children[0].path" :key='item.children[0].name'>
|
||||
<el-menu-item :index="item.path+'/'+item.children[0].path" class='submenu-title-noDropdown'>
|
||||
<svg-icon v-if='item.children[0].meta&&item.children[0].meta.icon' :icon-class="item.children[0].meta.icon"></svg-icon>
|
||||
<span v-if='item.children[0].meta&&item.children[0].meta.title'>{{item.children[0].meta.title}}</span>
|
||||
</el-menu-item>
|
||||
</router-link>
|
||||
<el-submenu :index="item.name" v-if="!item.noDropdown&&!item.hidden">
|
||||
|
||||
<el-submenu v-if="!item.hidden&&item.children&&item.children.length>1" :index="item.name||item.path" :key='item.name'>
|
||||
<template slot="title">
|
||||
<svg-icon v-if='item.icon' :icon-class="item.icon" /> {{item.name}}
|
||||
<svg-icon v-if='item.meta&&item.meta.icon' :icon-class="item.meta.icon"></svg-icon>
|
||||
<span v-if='item.meta&&item.meta.title'>{{item.meta.title}}</span>
|
||||
</template>
|
||||
<template v-for="child in item.children" v-if='!child.hidden'>
|
||||
<sidebar-item class='menu-indent' v-if='child.children&&child.children.length>0' :routes='[child]'> </sidebar-item>
|
||||
<router-link v-else class="menu-indent" :to="item.path+'/'+child.path">
|
||||
|
||||
<template v-if='!child.hidden' v-for="child in item.children">
|
||||
<sidebar-item class='nest-menu' v-if='child.children&&child.children.length>0' :routes='[child]' :key='child.path'></sidebar-item>
|
||||
|
||||
<router-link v-else :to="item.path+'/'+child.path" :key='child.name'>
|
||||
<el-menu-item :index="item.path+'/'+child.path">
|
||||
{{child.name}}
|
||||
<svg-icon v-if='child.meta&&child.meta.icon' :icon-class="child.meta.icon"></svg-icon>
|
||||
<span v-if='child.meta&&child.meta.title'>{{child.meta.title}}</span>
|
||||
</el-menu-item>
|
||||
</router-link>
|
||||
</template>
|
||||
</el-submenu>
|
||||
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -33,14 +41,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.svg-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.hideSidebar .menu-indent{
|
||||
display: block;
|
||||
text-indent: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
<template>
|
||||
<el-menu mode="vertical" theme="dark" :default-active="$route.path">
|
||||
<sidebar-item :routes="routes"></sidebar-item>
|
||||
</el-menu>
|
||||
<scroll-bar>
|
||||
<el-menu mode="vertical" unique-opened :default-active="$route.path" :collapse="isCollapse" background-color="#304156" text-color="#fff" active-text-color="#409EFF">
|
||||
<sidebar-item :routes='routes'></sidebar-item>
|
||||
</el-menu>
|
||||
</scroll-bar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import SidebarItem from './SidebarItem'
|
||||
import ScrollBar from '@/components/ScrollBar'
|
||||
|
||||
export default {
|
||||
components: { SidebarItem },
|
||||
components: { SidebarItem, ScrollBar },
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar'
|
||||
]),
|
||||
routes() {
|
||||
return this.$router.options.routes
|
||||
},
|
||||
isCollapse() {
|
||||
return !this.sidebar.opened
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.el-menu {
|
||||
min-height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue