improve: 侧边栏调整

This commit is contained in:
From-wh 2023-02-22 14:57:00 +08:00
parent 665fa35f72
commit 9f35ac237b
15 changed files with 359 additions and 116 deletions

View File

@ -1,4 +1,5 @@
.custom-bread-crumb {
display: inline-block;
vertical-align: top;
color: #fff;
}

View File

@ -2,6 +2,7 @@
width: 100%;
height: 100%;
position: relative;
color: #fff !important;
.custom-content-con {
float: right;
height: auto;

View File

@ -2,15 +2,15 @@
<div class="header-bar">
<sider-trigger :collapsed="collapsed" @on-change="handleCollpasedChange"></sider-trigger>
<span class="i-layout-header-trigger" @click="handleReload">
<Icon type="ios-refresh" />
<Icon type="ios-refresh" color='#fff' />
</span>
<custom-bread-crumb
<!-- <custom-bread-crumb
show-icon
style="margin-left: 30px"
:list="breadCrumbList"
:listLast="crumbPast"
:collapsed="collapsed"
></custom-bread-crumb>
></custom-bread-crumb> -->
<div class="custom-content-con">
<slot></slot>
</div>
@ -18,7 +18,6 @@
</template>
<style scoped lang="less">
.ivu-icon-ios-refresh {
color: #999 !important;
font-size: 23px;
}
.i-layout-header-trigger {

View File

@ -8,7 +8,7 @@
height: @size;
display: inline-block;
text-align: center;
color: #5c6b77;
color: #fff;
margin-top: 5px;
.iconcaidanshouqi {
.trans;

View File

@ -1,6 +1,6 @@
<template>
<a @click="handleChange" type="text" :class="['sider-trigger-a', collapsed ? 'collapsed' : '']"
><i class="iconfont" :class="collapsed ? 'iconcaidanzhankai' : 'iconcaidanshouqi'"></i
><i class="iconfont" color='#fff' :class="collapsed ? 'iconcaidanzhankai' : 'iconcaidanshouqi'"></i
></a>
</template>
<script>

View File

@ -24,7 +24,7 @@
font-size: 14px !important;
font-weight: 400;
line-height: 22px;
color: #515a6e;
color: #fff;
}
.header-notice .ivu-dropdown-item ~ .ivu-dropdown-item {
border-top: 1px solid #e8eaec;

View File

@ -9,28 +9,28 @@
<a
class="drop-menu-a"
type="text"
:class="{ on: parentItem.path == activeMenuPath }"
@mouseover="handleMousemove($event, children)"
:style="{ textAlign: !hideTitle ? 'left' : '' }"
><common-icon :size="rootIconSize" :color="textColor" :type="parentItem.icon" /><span
class="menu-title"
><common-icon :color="textColor" :type="parentItem.icon" /><Icon
style="float: right"
v-if="!hideTitle"
>{{ parentItem.title }}</span
><Icon style="float: right" v-if="!hideTitle" type="ios-arrow-forward" :size="16"
/></a>
type="ios-arrow-forward"
:size="16"
/>
<span class="title">{{ parentItem.title }}</span></a
>
<DropdownMenu ref="dropdown" slot="list">
<div v-for="child in children">
<template v-if="child.auth === undefined">
<collapsed-menu
class="child-menu"
v-if="showChildren(child)"
:icon-size="iconSize"
:parent-item="child"
:key="`drop-${child.path}`"
></collapsed-menu>
<DropdownItem v-else :key="`drop-${child.path}`" :name="child.path"
><common-icon :size="iconSize" :type="child.icon" /><span class="menu-title">{{
child.title
}}</span></DropdownItem
><common-icon :type="child.icon" /><span class="menu-title">{{ child.title }}1</span></DropdownItem
>
</template>
</div>
@ -54,6 +54,10 @@ export default {
type: Number,
default: 16,
},
activeMenuPath: {
type: String,
default: '',
},
},
data() {
return {

View File

@ -9,13 +9,13 @@
<template v-if="item.children && item.children.length === 1">
<side-menu-item v-if="showChildren(item)" :key="`menu${item.path}`" :parent-item="item"></side-menu-item>
<menu-item v-else :name="item.path" :key="`menu${item.children[0].path}`"
><common-icon :type="item.children[0].icon || ''" /><span>{{ item.children[0].title }}</span></menu-item
><common-icon :type="item.children[0].icon || ''" /><span class="title">{{ item.children[0].title }}</span></menu-item
>
</template>
<template v-else>
<side-menu-item v-if="showChildren(item)" :key="`menu${item.path}`" :parent-item="item"></side-menu-item>
<menu-item v-else :name="item.path" :key="`menu${item.path}`"
><common-icon :type="item.icon || ''" /><span>{{ item.title }}</span></menu-item
><common-icon :type="item.icon || ''" /><span class="title">{{ item.title }}</span></menu-item
>
</template>
</template>

View File

@ -1,18 +1,17 @@
.side-menu-wrapper {
user-select: none;
.menu-collapsed {
padding-top: 10px;
padding-top: 8px;
.ivu-dropdown {
width: 100%;
margin-bottom: 10px;
margin-bottom: 4px;
.ivu-dropdown-rel a {
width: 100%;
}
}
.ivu-tooltip {
width: 100%;
margin-bottom: 10px;
margin-bottom: 4px;
.ivu-tooltip-rel {
width: 100%;
@ -30,12 +29,15 @@
}
a.drop-menu-a {
display: inline-block;
padding: 6px 15px;
padding: 10px 15px 10px 10px;
width: 100%;
text-align: center;
color: #495060;
}
}
.menu-title {
padding-left: 6px;
.ivu-select-dropdown{
left: 95px !important;
}
.menu-title {
// padding-left: 6px;
}

View File

@ -1,39 +1,77 @@
<template>
<div class="side-menu-wrapper">
<slot></slot>
<Menu
ref="menu"
v-show="!collapsed"
:active-name="activeName"
:open-names="openMenus"
:accordion="accordion"
:theme="theme"
width="auto"
@on-open-change="openNameData"
@on-select="handleSelect"
>
<template v-for="item in menuList">
<template v-if="item.children && item.children.length === 1">
<side-menu-item v-if="showChildren(item)" :key="`menu-${item.path}`" :parent-item="item"></side-menu-item>
<menu-item v-else :name="item.path" :key="`menu-${item.children[0].path}`"
><common-icon :type="item.children[0].icon || ''" /><span>{{ item.children[0].title }}</span></menu-item
>
</template>
<template v-else>
<side-menu-item v-if="showChildren(item)" :key="`menu${item.path}`" :parent-item="item"></side-menu-item>
<menu-item v-else :name="item.path" :key="`menu${item.path}`"
><common-icon :type="item.icon || ''" /><span>{{ item.title }}</span></menu-item
>
</template>
</template>
</Menu>
<div class="side-menu-box" v-show="!collapsed">
<div class="parent-menu">
<Menu
ref="menu"
:active-name="activeMenuPath"
:open-names="openedNames"
:accordion="accordion"
:theme="theme"
width="75px"
@on-open-change="openNameData"
@on-select="handleSelect"
>
<template v-for="item in menuList">
<template>
<menu-item :name="item.path" :key="`menu${item.path}`"
><common-icon :type="item.icon || ''" /><span class="title">{{ item.title }}</span></menu-item
>
</template>
</template>
</Menu>
</div>
<div class="child-menu" v-if="childList.length">
<div class="cat-name">{{ catName }}</div>
<Menu
ref="childMenu"
:active-name="activePath"
:open-names="openMenus"
:accordion="accordion"
:theme="theme"
width="140px"
@on-open-change="openChildNameData"
@on-select="handleChildSelect"
>
<template v-for="item in childList">
<template v-if="item.auth === undefined">
<template v-if="item.children && item.children.length >= 1">
<side-menu-item
v-if="showChildren(item)"
:key="`menu${item.path}`"
:parent-item="item"
></side-menu-item>
<menu-item v-else :name="item.path" :key="`menu${item.path}`"
><common-icon :type="item.children[0].icon || ''" /><span class="title">{{
item.children[0].title
}}</span></menu-item
>
</template>
<template v-else>
<side-menu-item
v-if="showChildren(item)"
:key="`menu${item.path}`"
:parent-item="item"
></side-menu-item>
<menu-item v-else :name="item.path" :key="`menu${item.path}`"
><common-icon :type="item.icon || ''" /><span class="title">{{ item.title }}</span></menu-item
>
</template>
</template>
</template>
</Menu>
</div>
</div>
<div class="menu-collapsed" v-show="collapsed" :list="menuList">
<template v-for="item in menuList">
<collapsed-menu
v-if="item.children && item.children.length > 0"
@on-click="handleSelect"
hide-title
:hide-title="true"
:activeMenuPath="activeMenuPath"
:root-icon-size="rootIconSize"
:icon-size="iconSize"
:theme="theme"
@ -41,12 +79,14 @@
:key="`drop-menu-${item.path}`"
></collapsed-menu>
<Tooltip transfer v-else :content="item.title" placement="right" :key="`drop-menu-${item.path}`">
<a @click="handleSelect(getNameOrHref(item, true))" class="drop-menu-a" :style="{ textAlign: 'center' }"
><common-icon
:size="rootIconSize"
:color="textColor"
:type="item.icon || (item.children && item.children[0].icon)"
/></a>
<a
@click="handleSelect(item)"
class="drop-menu-a"
:class="{ on: item.path == activeMenuPath }"
:style="{ textAlign: 'center' }"
><common-icon :color="textColor" :type="item.icon || (item.children && item.children[0].icon)" />
<span class="title">{{ item.title }}</span>
</a>
</Tooltip>
</template>
</div>
@ -58,10 +98,11 @@ import CollapsedMenu from './collapsed-menu.vue';
import { getUnion } from '@/libs/tools';
import { mapState } from 'vuex';
import mixin from './mixin';
import itemMixin from './item-mixin';
export default {
name: 'SideMenu',
mixins: [mixin],
mixins: [mixin, itemMixin],
components: {
SideMenuItem,
CollapsedMenu,
@ -78,7 +119,7 @@ export default {
},
theme: {
type: String,
default: 'dark',
default: 'light',
},
rootIconSize: {
type: Number,
@ -89,10 +130,6 @@ export default {
default: 16,
},
accordion: Boolean,
activeName: {
type: String,
default: '',
},
openNames: {
type: Array,
default: () => [],
@ -101,12 +138,56 @@ export default {
data() {
return {
openedNames: [],
childList: [],
activeChildName: '',
childOptions: [],
activePath: '',
activeMenuPath: '',
catName: '',
};
},
methods: {
handleSelect(name) {
this.$emit('on-select', name);
// this.$store.commit('menus/getopenMenus', this.openedNames)
handleSelect(name, type) {
if (!type) {
this.$emit('on-select', name);
}
this.childOptions = [];
this.menuList.map((e) => {
if (e.path === name) {
console.log(e, 'eeee');
if (e.children) {
this.catName = e.title;
this.activeMenuPath = e.path;
this.childList = e.children || [];
this.activeChildName = e.children[0].path;
this.childOptions = [e.children[0].path];
this.$store.commit('menus/childMenuList', this.childList);
} else {
this.childList = [];
this.$store.commit('menus/childMenuList', []);
}
}
});
},
handleChildSelect(name) {
this.turnToPage(name);
},
turnToPage(route, all) {
let { path, name, params, query } = {};
if (typeof route === 'string' && !all) path = route;
else if (typeof route === 'string' && all) name = route;
else {
path = route.path;
name = route.name;
params = route.params;
query = route.query;
}
this.$router.push({
path,
name,
params,
query,
});
},
getOpenedNamesByActiveName() {
return this.$route.matched.map((item) => item.path).filter((item) => item !== name);
@ -119,6 +200,17 @@ export default {
// this.openedNames = n
// this.$store.commit('menus/getopenMenus', n)
},
openChildNameData(e) {
console.log(e);
},
handleUpdateMenuState() {
this.$nextTick(() => {
if (this.$refs.childMenu) {
this.$refs.childMenu.updateActiveName();
if (this.accordion) this.$refs.childMenu.updateOpened();
}
});
},
},
computed: {
...mapState('menus', ['openMenus']),
@ -130,18 +222,32 @@ export default {
activeName(name) {
if (this.accordion) this.openedNames = this.getOpenedNamesByActiveName();
else this.openedNames = getUnion(this.openedNames, this.getOpenedNamesByActiveName());
// this.handleSelect(this.activeName);
},
openNames(newNames) {
this.openedNames = newNames;
},
openedNames() {
this.$nextTick(() => {
// this.$refs.menu.updateOpened()
this.$refs.menu.updateOpened();
});
},
$route(newRoute) {},
$route: {
handler(newRoute) {
console.log(newRoute, 'newRoutenewRoute');
this.activePath = newRoute.path;
this.activeMenuPath = newRoute.matched[0].path;
this.handleUpdateMenuState();
console.log(activeMenuPath, 'activeMenuPath');
},
immediate: true,
},
},
mounted() {
this.openedNames = getUnion(this.openedNames, this.getOpenedNamesByActiveName());
this.handleSelect(this.openedNames[0], 'one');
this.activeMenuPath = this.openedNames[0];
},
};
</script>
@ -149,8 +255,9 @@ export default {
@import './side-menu.less';
.ivu-menu {
.side-menu-wrapper a.drop-menu-a {
padding: 15px !important;
padding: 1px !important;
}
.ivu-select-dropdown.ivu-dropdown-transfer {
background: rgb(0, 21, 41) !important;
width: 170px !important;
@ -191,6 +298,8 @@ export default {
> .drop-menu-a
> .menu-title {
color: #fff !important;
font-size: 14px;
line-height: 14px;
}
.ivu-select-dropdown.ivu-dropdown-transfer
.collased-menu-dropdown:hover
@ -200,4 +309,124 @@ export default {
color: #fff !important;
}
}
.side-menu-wrapper a.drop-menu-a {
display: flex;
align-items: center;
justify-content: center;
}
.side-menu-box {
display: flex;
.drop-menu-a {
font-size: 14px;
line-height: 14px;
display: flex;
align-items: center;
padding: 10px 10px;
margin-bottom: 4px;
.ivu-icon {
font-size: 14px;
margin-right: 8px;
}
}
.parent-menu {
z-index: 99;
padding: 0 8px;
box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.06);
height: calc(~'100vh - 50px');
.ivu-menu-item-selected {
background-color: #1890ff !important;
color: #fff !important;
border-radius: 4px;
}
.ivu-menu-vertical .ivu-menu-item {
padding: 10px 10px;
margin-bottom: 8px;
display: flex;
align-items: center;
.title {
line-height: 14px;
}
}
.ivu-menu-vertical .ivu-menu-item:first-child {
margin-top: 8px;
}
}
.child-menu {
z-index: 88;
.ivu-menu-vertical .ivu-menu-item {
padding: 12px 10px;
display: flex;
align-items: center;
.title {
line-height: 14px;
}
}
.ivu-menu-submenu {
.ivu-menu-item {
padding-left: 16px !important;
}
.ivu-menu-submenu {
.ivu-menu-submenu-title {
padding-left: 16px !important;
}
}
}
.ivu-menu-vertical .ivu-menu-submenu-title {
padding: 12px 10px;
line-height: 16px;
}
.cat-name {
font-size: 16px;
line-height: 16px;
font-weight: 600;
color: #303133;
padding: 18px;
border-bottom: 1px solid #eee;
}
}
> .ivu-menu {
padding: 8px;
}
.ivu-menu-vertical.ivu-menu-light:after {
width: 0px !important;
}
.ivu-menu-light.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu):after {
width: 0px;
}
}
.menu-collapsed {
padding: 0 8px;
.drop-menu-a.on {
background-color: #1890ff !important;
color: #fff !important;
border-radius: 4px;
.ivu-icon {
color: #fff !important;
}
}
.drop-menu-a {
font-size: 14px;
line-height: 14px;
display: flex;
align-items: center;
padding: 10px 11px;
margin-bottom: 4px;
flex-wrap: nowrap;
.ivu-icon {
font-size: 14px;
margin-right: 8px;
}
.title {
white-space: nowrap;
}
}
.drop-menu-a {
padding: 0;
}
.collased-menu-dropdown * {
font-size: 14px;
}
}
</style>

View File

@ -1,7 +1,6 @@
.main {
.logo-con {
height: 64px;
padding: 10px;
height: 50px;
img {
height: 44px;
width: auto;
@ -23,7 +22,7 @@
overflow: hidden;
}
.main-content-con {
height: ~'calc(100% - 60px)';
height: ~'calc(100% - 70px)';
overflow: hidden;
}
.tag-nav-wrapper {
@ -32,14 +31,14 @@
background: #f0f0f0;
}
.content-wrapper {
padding: 18px;
padding: 16px;
height: ~'calc(100% - 80px)';
overflow: auto;
}
.left-sider {
.ivu-layout-sider-children {
overflow-y: scroll;
margin-right: -18px;
margin-right: -16px;
overflow-x: hidden;
}
}

View File

@ -1,45 +1,45 @@
<template>
<Layout style="height: 100%" class="main">
<Sider
hide-trigger
collapsible
:width="200"
:collapsed-width="isMobile ? 0 : 80"
v-model="collapsed"
class="left-sider"
:style="{ overflow: 'hidden' }"
v-if="!headMenuNoShow"
>
<side-menu
accordion
ref="sideMenu"
:active-name="$route.path"
:collapsed="collapsed"
@on-select="turnToPage"
:menu-list="menuList"
>
<!-- 需要放在菜单上面的内容,如Logo,写在side-menu标签内部,如下 -->
<div class="logo-con">
<img v-show="!collapsed" :src="maxLogo" key="max-logo" />
<img v-show="collapsed" :src="minLogo" key="min-logo" />
</div>
</side-menu>
</Sider>
<Header class="header-con" v-if="!headMenuNoShow">
<div class="logo-con">
<img v-show="!collapsed" :src="maxLogo" key="max-logo" />
<img v-show="collapsed" :src="minLogo" key="min-logo" />
</div>
<header-bar :collapsed="collapsed" @on-coll-change="handleCollapsedChange" @on-reload="handleReload">
<user :message-unread-count="unreadCount" :user-avatar="userAvatar" />
<language v-if="$config.useI18n" @on-lang-change="setLocal" style="margin-right: 10px" :lang="local" />
<header-notice></header-notice>
<fullscreen v-model="isFullscreen" style="margin-right: 10px" />
<error-store
v-if="$config.plugin['error-store'] && $config.plugin['error-store'].showInHeader"
:has-read="hasReadErrorPage"
:count="errorCount"
></error-store>
<header-search></header-search>
</header-bar>
</Header>
<Layout>
<Header class="header-con" v-if="!headMenuNoShow">
<header-bar :collapsed="collapsed" @on-coll-change="handleCollapsedChange" @on-reload="handleReload">
<user :message-unread-count="unreadCount" :user-avatar="userAvatar" />
<language v-if="$config.useI18n" @on-lang-change="setLocal" style="margin-right: 10px" :lang="local" />
<header-notice></header-notice>
<fullscreen v-model="isFullscreen" style="margin-right: 10px" />
<error-store
v-if="$config.plugin['error-store'] && $config.plugin['error-store'].showInHeader"
:has-read="hasReadErrorPage"
:count="errorCount"
></error-store>
<header-search></header-search>
</header-bar>
</Header>
<Sider
hide-trigger
collapsible
:width="childMenuList.length ? 220 : 90"
:collapsed-width="isMobile ? 0 : 90"
v-model="collapsed"
class="left-sider"
:style="{ overflow: 'hidden' }"
v-if="!headMenuNoShow"
>
<side-menu
accordion
ref="sideMenu"
:active-name="$route.path"
:collapsed="collapsed"
@on-select="turnToPage"
:menu-list="menuList"
>
<!-- 需要放在菜单上面的内容,如Logo,写在side-menu标签内部,如下 -->
</side-menu>
</Sider>
<Content class="main-content-con">
<Layout class="main-layout-con">
<div class="tag-nav-wrapper" v-if="!headMenuNoShow">
@ -115,6 +115,7 @@ export default {
};
},
computed: {
...mapState('menus', ['childMenuList']),
...mapGetters(['errorCount']),
...mapState('media', ['isMobile']),
tagNavList() {
@ -281,10 +282,13 @@ export default {
</script>
<style lang="less">
.main .header-con {
padding: 0 20px 0 0px;
padding: 0 0px 0 0px;
display: flex;
background: linear-gradient(270deg, #1570ef 0%, #1570ef 100%);
}
.main .logo-con img {
height: 50px;
transition: all 1s;
}
.main .tag-nav-wrapper {
// height: 10px;

View File

@ -2,4 +2,4 @@
@menu-dark-title: #001529;
@menu-dark-active-bg: #000c17;
@layout-sider-background: #001529;
@layout-sider-background: #fff;

View File

@ -25,6 +25,7 @@ export default {
state: {
menusName: getMenusName(),
openMenus: [],
childMenuList: [],
},
mutations: {
getmenusNav(state, menuList) {
@ -36,6 +37,9 @@ export default {
setopenMenus(state, openList) {
state.openMenus = openList;
},
childMenuList(state, list) {
state.childMenuList = list;
},
},
actions: {
getMenusNavList({ commit }) {

View File

@ -225,7 +225,7 @@ body {
}
.ivu-icon-ios-refresh {
color: #1890ff !important;
color: #1890ff;
}
.product_tabs .ivu-tabs-bar {