mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 14:47:28 +08:00
feat(layout): added setting. Used to fix the left mixed mode menu
This commit is contained in:
@@ -75,6 +75,7 @@ export default defineComponent({
|
||||
getIsMixSidebar,
|
||||
getCloseMixSidebarOnChange,
|
||||
getMixSideTrigger,
|
||||
getMixSideFixed,
|
||||
} = useMenuSetting();
|
||||
|
||||
const {
|
||||
@@ -110,6 +111,12 @@ export default defineComponent({
|
||||
def={unref(getSplit)}
|
||||
disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('layout.setting.mixSidebarFixed')}
|
||||
event={HandlerEnum.MENU_FIXED_MIX_SIDEBAR}
|
||||
def={unref(getMixSideFixed)}
|
||||
disabled={!unref(getIsMixSidebar)}
|
||||
/>
|
||||
|
||||
<SwitchItem
|
||||
title={t('layout.setting.closeMixSidebarOnChange')}
|
||||
|
@@ -27,6 +27,7 @@ export enum HandlerEnum {
|
||||
MENU_FIXED,
|
||||
MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE,
|
||||
MENU_TRIGGER_MIX_SIDEBAR,
|
||||
MENU_FIXED_MIX_SIDEBAR,
|
||||
|
||||
// header
|
||||
HEADER_SHOW,
|
||||
|
@@ -70,6 +70,9 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
|
||||
case HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR:
|
||||
return { menuSetting: { mixSideTrigger: value } };
|
||||
|
||||
case HandlerEnum.MENU_FIXED_MIX_SIDEBAR:
|
||||
return { menuSetting: { mixSideTrigger: value } };
|
||||
|
||||
// ============transition==================
|
||||
case HandlerEnum.OPEN_PAGE_LOADING:
|
||||
appStore.commitPageLoadingState(false);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="`${prefixCls}-dom`" />
|
||||
<div :class="`${prefixCls}-dom`" :style="getDomStyle" />
|
||||
|
||||
<div
|
||||
v-click-outside="handleClickOutside"
|
||||
@@ -27,7 +27,7 @@
|
||||
v-bind="getItemEvents(item)"
|
||||
>
|
||||
<MenuTag :item="item" :showTitle="false" :isHorizontal="false" />
|
||||
<g-icon
|
||||
<Icon
|
||||
:class="`${prefixCls}-module__icon`"
|
||||
:size="22"
|
||||
:icon="item.meta && item.meta.icon"
|
||||
@@ -48,6 +48,14 @@
|
||||
]"
|
||||
>
|
||||
<span class="text"> {{ title }}</span>
|
||||
<Icon
|
||||
:size="16"
|
||||
v-if="getMixSideFixed"
|
||||
icon="ri:pushpin-2-fill"
|
||||
class="pushpin"
|
||||
@click="handleFixedMenu"
|
||||
/>
|
||||
<Icon :size="16" v-else icon="ri:pushpin-2-line" class="pushpin" @click="handleFixedMenu" />
|
||||
</div>
|
||||
<ScrollContainer :class="`${prefixCls}-menu-list__content`">
|
||||
<BasicMenu
|
||||
@@ -70,20 +78,23 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, computed, CSSProperties, unref } from 'vue';
|
||||
import type { Menu } from '/@/router/types';
|
||||
import type { RouteLocationNormalized } from 'vue-router';
|
||||
import { RouteLocationNormalized } from 'vue-router';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { getShallowMenus, getChildrenMenus, getCurrentParentPath } from '/@/router/menus';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { ScrollContainer } from '/@/components/Container';
|
||||
import Icon from '/@/components/Icon';
|
||||
import { AppLogo } from '/@/components/Application';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
import { BasicMenu, MenuTag } from '/@/components/Menu';
|
||||
import { listenerLastChangeTab } from '/@/logics/mitt/tabChange';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDragLine } from './useLayoutSider';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
|
||||
import { SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
|
||||
|
||||
import clickOutside from '/@/directives/clickOutside';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutMixSider',
|
||||
@@ -92,6 +103,7 @@
|
||||
AppLogo,
|
||||
BasicMenu,
|
||||
MenuTag,
|
||||
Icon,
|
||||
},
|
||||
directives: {
|
||||
clickOutside,
|
||||
@@ -101,6 +113,7 @@
|
||||
const activePath = ref('');
|
||||
const chilrenMenus = ref<Menu[]>([]);
|
||||
const openMenu = ref(false);
|
||||
const isInit = ref(false);
|
||||
const dragBarRef = ref<ElRef>(null);
|
||||
const sideRef = ref<ElRef>(null);
|
||||
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null);
|
||||
@@ -114,7 +127,12 @@
|
||||
getCloseMixSidebarOnChange,
|
||||
getMenuTheme,
|
||||
getMixSideTrigger,
|
||||
getRealWidth,
|
||||
getMixSideFixed,
|
||||
mixSideHasChildren,
|
||||
setMenuSetting,
|
||||
} = useMenuSetting();
|
||||
|
||||
const { title } = useGlobSetting();
|
||||
|
||||
useDragLine(sideRef, dragBarRef, true);
|
||||
@@ -127,14 +145,41 @@
|
||||
}
|
||||
);
|
||||
|
||||
const getIsFixed = computed(() => {
|
||||
mixSideHasChildren.value = unref(chilrenMenus).length > 0;
|
||||
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren);
|
||||
if (isFixed) {
|
||||
openMenu.value = true;
|
||||
}
|
||||
return isFixed;
|
||||
});
|
||||
|
||||
const getDomStyle = computed(
|
||||
(): CSSProperties => {
|
||||
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0;
|
||||
const width = `${SIDE_BAR_SHOW_TIT_MINI_WIDTH + fixedWidth}px`;
|
||||
return {
|
||||
width,
|
||||
maxWidth: width,
|
||||
minWidth: width,
|
||||
flex: `0 0 ${width}`,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const getMenuEvents = computed(() => {
|
||||
return unref(getMixSideTrigger) === 'hover'
|
||||
? {
|
||||
onMouseleave: () => {
|
||||
openMenu.value = false;
|
||||
},
|
||||
}
|
||||
: {};
|
||||
// return unref(getMixSideTrigger) === 'hover'
|
||||
// ? {
|
||||
// onMouseleave: () => {
|
||||
// closeMenu();
|
||||
// },
|
||||
// }
|
||||
// : {};
|
||||
return {
|
||||
onMouseleave: () => {
|
||||
closeMenu();
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const getShowDragBar = computed(() => unref(getCanDrag));
|
||||
@@ -145,9 +190,9 @@
|
||||
|
||||
listenerLastChangeTab((route) => {
|
||||
currentRoute.value = route;
|
||||
setActive();
|
||||
setActive(true);
|
||||
if (unref(getCloseMixSidebarOnChange)) {
|
||||
openMenu.value = false;
|
||||
closeMenu();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -156,7 +201,11 @@
|
||||
|
||||
if (unref(activePath) === path) {
|
||||
if (!hover) {
|
||||
openMenu.value = !unref(openMenu);
|
||||
if (!unref(openMenu)) {
|
||||
openMenu.value = true;
|
||||
} else {
|
||||
closeMenu();
|
||||
}
|
||||
}
|
||||
if (!unref(openMenu)) {
|
||||
setActive();
|
||||
@@ -169,18 +218,32 @@
|
||||
if (!children || children.length === 0) {
|
||||
go(path);
|
||||
chilrenMenus.value = [];
|
||||
openMenu.value = false;
|
||||
closeMenu();
|
||||
return;
|
||||
}
|
||||
chilrenMenus.value = children;
|
||||
}
|
||||
|
||||
async function setActive() {
|
||||
async function setActive(setChildren = false) {
|
||||
const path = currentRoute.value?.path;
|
||||
if (!path) return;
|
||||
const parentPath = await getCurrentParentPath(path);
|
||||
activePath.value = parentPath;
|
||||
// hanldeModuleClick(parentPath);
|
||||
if (unref(getMixSideFixed)) {
|
||||
const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
|
||||
const p = activeMenu?.path;
|
||||
if (p) {
|
||||
const children = await getChildrenMenus(p);
|
||||
if (setChildren) {
|
||||
chilrenMenus.value = children;
|
||||
openMenu.value = children.length > 0;
|
||||
}
|
||||
if (children.length === 0) {
|
||||
chilrenMenus.value = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleMenuClick(path: string) {
|
||||
@@ -188,7 +251,7 @@
|
||||
}
|
||||
|
||||
function handleClickOutside() {
|
||||
openMenu.value = false;
|
||||
closeMenu();
|
||||
setActive();
|
||||
}
|
||||
|
||||
@@ -203,6 +266,18 @@
|
||||
};
|
||||
}
|
||||
|
||||
function handleFixedMenu() {
|
||||
setMenuSetting({
|
||||
mixSideFixed: !unref(getIsFixed),
|
||||
});
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
if (!unref(getIsFixed)) {
|
||||
openMenu.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
@@ -221,6 +296,9 @@
|
||||
getMenuTheme,
|
||||
getItemEvents,
|
||||
getMenuEvents,
|
||||
getDomStyle,
|
||||
handleFixedMenu,
|
||||
getMixSideFixed,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -241,7 +319,7 @@
|
||||
min-width: @width;
|
||||
overflow: hidden;
|
||||
background: @sider-dark-bg-color;
|
||||
transition: all 0.2s ease 0s;
|
||||
transition: all 0.3s ease 0s;
|
||||
flex: 0 0 @width;
|
||||
.@{tag-prefix-cls} {
|
||||
position: absolute;
|
||||
@@ -293,6 +371,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.@{prefix-cls}-menu-list {
|
||||
&__title {
|
||||
.pushpin {
|
||||
color: rgba(0, 0, 0, 0.35);
|
||||
|
||||
&:hover {
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@border-color: @sider-dark-lighten-1-bg-color;
|
||||
|
||||
@@ -388,20 +477,30 @@
|
||||
&__title {
|
||||
display: flex;
|
||||
height: @header-height;
|
||||
margin-left: -6px;
|
||||
// margin-left: -6px;
|
||||
font-size: 18px;
|
||||
color: @primary-color;
|
||||
border-bottom: 1px solid rgb(238, 238, 238);
|
||||
opacity: 0;
|
||||
transition: unset;
|
||||
// justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
justify-content: space-between;
|
||||
|
||||
&.show {
|
||||
min-width: 130px;
|
||||
opacity: 1;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.pushpin {
|
||||
margin-right: 6px;
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
|
Reference in New Issue
Block a user