mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 14:13:40 +08:00
fix(menu): improve menu logic, fix #461
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
- 登录页样式修复
|
- 登录页样式修复
|
||||||
|
- 修复菜单已知问题
|
||||||
|
|
||||||
## 2.2.0 (2021-04-06)
|
## 2.2.0 (2021-04-06)
|
||||||
|
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
v-if="getShowDarkModeToggle"
|
v-if="getShowDarkModeToggle"
|
||||||
:class="[
|
:class="[
|
||||||
prefixCls,
|
prefixCls,
|
||||||
`${prefixCls}--${size}`,
|
|
||||||
{
|
{
|
||||||
[`${prefixCls}--dark`]: isDark,
|
[`${prefixCls}--dark`]: isDark,
|
||||||
},
|
},
|
||||||
@@ -30,13 +29,13 @@
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'DarkModeToggle',
|
name: 'DarkModeToggle',
|
||||||
components: { SvgIcon },
|
components: { SvgIcon },
|
||||||
props: {
|
// props: {
|
||||||
size: {
|
// size: {
|
||||||
type: String,
|
// type: String,
|
||||||
default: 'default',
|
// default: 'default',
|
||||||
validate: (val) => ['default', 'large'].includes(val),
|
// validate: (val) => ['default', 'large'].includes(val),
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
setup() {
|
setup() {
|
||||||
const { prefixCls } = useDesign('dark-mode-toggle');
|
const { prefixCls } = useDesign('dark-mode-toggle');
|
||||||
const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
|
const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
|
||||||
@@ -97,15 +96,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&--large {
|
// &--large {
|
||||||
width: 72px;
|
// width: 70px;
|
||||||
height: 34px;
|
// height: 34px;
|
||||||
padding: 0 10px;
|
// padding: 0 10px;
|
||||||
|
|
||||||
.@{prefix-cls}-inner {
|
// .@{prefix-cls}-inner {
|
||||||
width: 26px;
|
// width: 26px;
|
||||||
height: 26px;
|
// height: 26px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -24,8 +24,6 @@
|
|||||||
import Iconify from '@purge-icons/generated';
|
import Iconify from '@purge-icons/generated';
|
||||||
import { isString } from '/@/utils/is';
|
import { isString } from '/@/utils/is';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
|
||||||
import { ThemeEnum } from '/@/enums/appEnum';
|
|
||||||
|
|
||||||
const SVG_END_WITH_FLAG = '|svg';
|
const SVG_END_WITH_FLAG = '|svg';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -46,8 +44,6 @@
|
|||||||
setup(props) {
|
setup(props) {
|
||||||
const elRef = ref<ElRef>(null);
|
const elRef = ref<ElRef>(null);
|
||||||
|
|
||||||
const { getDarkMode } = useRootSetting();
|
|
||||||
|
|
||||||
const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG));
|
const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG));
|
||||||
const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, ''));
|
const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, ''));
|
||||||
const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`);
|
const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`);
|
||||||
@@ -85,7 +81,7 @@
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
fontSize: `${fs}px`,
|
fontSize: `${fs}px`,
|
||||||
color: color || (unref(getDarkMode) === ThemeEnum.DARK ? '#fff' : '#303133'),
|
color: color,
|
||||||
display: 'inline-flex',
|
display: 'inline-flex',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<Menu
|
<Menu
|
||||||
v-bind="getBindValues"
|
v-bind="getBindValues"
|
||||||
@select="handleSelect"
|
|
||||||
:activeName="activeName"
|
:activeName="activeName"
|
||||||
:openNames="getOpenKeys"
|
:openNames="getOpenKeys"
|
||||||
:class="prefixCls"
|
:class="prefixCls"
|
||||||
:activeSubMenuNames="activeSubMenuNames"
|
:activeSubMenuNames="activeSubMenuNames"
|
||||||
|
@select="handleSelect"
|
||||||
|
@open-change="handleOpenChange"
|
||||||
>
|
>
|
||||||
<template v-for="item in items" :key="item.path">
|
<template v-for="item in items" :key="item.path">
|
||||||
<SimpleSubMenu
|
<SimpleSubMenu
|
||||||
@@ -53,6 +54,7 @@
|
|||||||
beforeClickFn: {
|
beforeClickFn: {
|
||||||
type: Function as PropType<(key: string) => Promise<boolean>>,
|
type: Function as PropType<(key: string) => Promise<boolean>>,
|
||||||
},
|
},
|
||||||
|
isSplitMenu: propTypes.bool,
|
||||||
},
|
},
|
||||||
emits: ['menuClick'],
|
emits: ['menuClick'],
|
||||||
setup(props, { attrs, emit }) {
|
setup(props, { attrs, emit }) {
|
||||||
@@ -94,6 +96,9 @@
|
|||||||
watch(
|
watch(
|
||||||
() => props.items,
|
() => props.items,
|
||||||
() => {
|
() => {
|
||||||
|
if (!props.isSplitMenu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setOpenKeys(currentRoute.value.path);
|
setOpenKeys(currentRoute.value.path);
|
||||||
},
|
},
|
||||||
{ flush: 'post' }
|
{ flush: 'post' }
|
||||||
@@ -135,11 +140,17 @@
|
|||||||
menuState.activeName = key;
|
menuState.activeName = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleOpenChange(v) {
|
||||||
|
console.log('======================');
|
||||||
|
console.log(v);
|
||||||
|
console.log('======================');
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
getBindValues,
|
getBindValues,
|
||||||
handleSelect,
|
handleSelect,
|
||||||
getOpenKeys,
|
getOpenKeys,
|
||||||
|
handleOpenChange,
|
||||||
...toRefs(menuState),
|
...toRefs(menuState),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@@ -138,6 +138,15 @@
|
|||||||
});
|
});
|
||||||
emit('select', name);
|
emit('select', name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
rootMenuEmitter.on('open-name-change', ({ name, opened }) => {
|
||||||
|
if (opened && !openedNames.value.includes(name)) {
|
||||||
|
openedNames.value.push(name);
|
||||||
|
} else if (!opened) {
|
||||||
|
const index = openedNames.value.findIndex((item) => item === name);
|
||||||
|
index !== -1 && openedNames.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return { getClass, openedNames };
|
return { getClass, openedNames };
|
||||||
|
@@ -66,11 +66,16 @@
|
|||||||
|
|
||||||
function handleClickItem() {
|
function handleClickItem() {
|
||||||
const { disabled } = props;
|
const { disabled } = props;
|
||||||
if (disabled) return;
|
if (disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rootMenuEmitter.emit('on-menu-item-select', props.name);
|
rootMenuEmitter.emit('on-menu-item-select', props.name);
|
||||||
if (unref(getCollapse)) return;
|
if (unref(getCollapse)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const { uidList } = getParentList();
|
const { uidList } = getParentList();
|
||||||
|
|
||||||
rootMenuEmitter.emit('on-update-opened', {
|
rootMenuEmitter.emit('on-update-opened', {
|
||||||
opend: false,
|
opend: false,
|
||||||
parent: instance?.parent,
|
parent: instance?.parent,
|
||||||
|
@@ -43,8 +43,9 @@
|
|||||||
:class="`${prefixCls}-submenu-title-icon`"
|
:class="`${prefixCls}-submenu-title-icon`"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<template #content>
|
<!-- eslint-disable-next-line -->
|
||||||
<div v-bind="getEvents(true)" v-show="opened">
|
<template #content v-show="opened">
|
||||||
|
<div v-bind="getEvents(true)">
|
||||||
<ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]">
|
<ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -78,7 +79,7 @@
|
|||||||
import { isBoolean, isObject } from '/@/utils/is';
|
import { isBoolean, isObject } from '/@/utils/is';
|
||||||
import Mitt from '/@/utils/mitt';
|
import Mitt from '/@/utils/mitt';
|
||||||
|
|
||||||
const DELAY = 250;
|
const DELAY = 200;
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SubMenu',
|
name: 'SubMenu',
|
||||||
components: {
|
components: {
|
||||||
@@ -189,6 +190,7 @@
|
|||||||
const { disabled } = props;
|
const { disabled } = props;
|
||||||
if (disabled || unref(getCollapse)) return;
|
if (disabled || unref(getCollapse)) return;
|
||||||
const opened = state.opened;
|
const opened = state.opened;
|
||||||
|
|
||||||
if (unref(getAccordion)) {
|
if (unref(getAccordion)) {
|
||||||
const { uidList } = getParentList();
|
const { uidList } = getParentList();
|
||||||
rootMenuEmitter.emit('on-update-opened', {
|
rootMenuEmitter.emit('on-update-opened', {
|
||||||
@@ -196,6 +198,11 @@
|
|||||||
parent: instance?.parent,
|
parent: instance?.parent,
|
||||||
uidList: uidList,
|
uidList: uidList,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
rootMenuEmitter.emit('open-name-change', {
|
||||||
|
name: props.name,
|
||||||
|
opened: !opened,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
state.opened = !opened;
|
state.opened = !opened;
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ import { uniq } from 'lodash-es';
|
|||||||
import { getAllParentPath } from '/@/router/helper/menuHelper';
|
import { getAllParentPath } from '/@/router/helper/menuHelper';
|
||||||
|
|
||||||
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
|
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
|
||||||
import { useDebounce } from '../../../hooks/core/useDebounce';
|
import { useDebounce } from '/@/hooks/core/useDebounce';
|
||||||
|
|
||||||
export function useOpenKeys(
|
export function useOpenKeys(
|
||||||
menuState: MenuState,
|
menuState: MenuState,
|
||||||
|
@@ -49,6 +49,7 @@
|
|||||||
getAccordion,
|
getAccordion,
|
||||||
getIsHorizontal,
|
getIsHorizontal,
|
||||||
getIsSidebarType,
|
getIsSidebarType,
|
||||||
|
getSplit,
|
||||||
} = useMenuSetting();
|
} = useMenuSetting();
|
||||||
const { getShowLogo } = useRootSetting();
|
const { getShowLogo } = useRootSetting();
|
||||||
|
|
||||||
@@ -144,7 +145,7 @@
|
|||||||
// console.log(menus);
|
// console.log(menus);
|
||||||
if (!menus || !menus.length) return null;
|
if (!menus || !menus.length) return null;
|
||||||
return !props.isHorizontal ? (
|
return !props.isHorizontal ? (
|
||||||
<SimpleMenu {...menuProps} items={menus} />
|
<SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} />
|
||||||
) : (
|
) : (
|
||||||
<BasicMenu
|
<BasicMenu
|
||||||
{...menuProps}
|
{...menuProps}
|
||||||
|
@@ -408,7 +408,7 @@ export default defineComponent({
|
|||||||
wrapClassName="setting-drawer"
|
wrapClassName="setting-drawer"
|
||||||
>
|
>
|
||||||
{unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
|
{unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
|
||||||
{unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" size="large" />}
|
{unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" />}
|
||||||
<Divider>{() => t('layout.setting.navMode')}</Divider>
|
<Divider>{() => t('layout.setting.navMode')}</Divider>
|
||||||
{renderSidebar()}
|
{renderSidebar()}
|
||||||
<Divider>{() => t('layout.setting.sysTheme')}</Divider>
|
<Divider>{() => t('layout.setting.sysTheme')}</Divider>
|
||||||
|
@@ -82,7 +82,7 @@ html[data-theme='dark'] {
|
|||||||
.ant-tabs-tab-active {
|
.ant-tabs-tab-active {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 18px;
|
padding-left: 18px;
|
||||||
color: @white;
|
color: @white !important;
|
||||||
background: @primary-color;
|
background: @primary-color;
|
||||||
border: 0;
|
border: 0;
|
||||||
transition: none;
|
transition: none;
|
||||||
|
@@ -7,7 +7,7 @@ const charts: AppRouteModule = {
|
|||||||
path: '/charts',
|
path: '/charts',
|
||||||
name: 'Charts',
|
name: 'Charts',
|
||||||
component: LAYOUT,
|
component: LAYOUT,
|
||||||
redirect: '/charts/apexChart',
|
redirect: '/charts/echarts/map',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ion:bar-chart-outline',
|
icon: 'ion:bar-chart-outline',
|
||||||
title: t('routes.demo.charts.charts'),
|
title: t('routes.demo.charts.charts'),
|
||||||
|
@@ -112,6 +112,10 @@
|
|||||||
&-form {
|
&-form {
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-iconify {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user