mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 04:39:12 +08:00
fix(menu): ensure the menu is activated correctly,fix #432
This commit is contained in:
@@ -34,7 +34,7 @@
|
|||||||
"@iconify/iconify": "^2.0.0-rc.6",
|
"@iconify/iconify": "^2.0.0-rc.6",
|
||||||
"@vueuse/core": "^4.6.2",
|
"@vueuse/core": "^4.6.2",
|
||||||
"@zxcvbn-ts/core": "^0.3.0",
|
"@zxcvbn-ts/core": "^0.3.0",
|
||||||
"ant-design-vue": "2.1.0",
|
"ant-design-vue": "2.1.1",
|
||||||
"apexcharts": "^3.26.0",
|
"apexcharts": "^3.26.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.0.0",
|
||||||
|
@@ -18,7 +18,6 @@
|
|||||||
</Menu>
|
</Menu>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PropType } from 'vue';
|
|
||||||
import type { MenuState } from './types';
|
import type { MenuState } from './types';
|
||||||
import type { Menu as MenuType } from '/@/router/types';
|
import type { Menu as MenuType } from '/@/router/types';
|
||||||
|
|
||||||
@@ -69,6 +68,7 @@
|
|||||||
const { currentRoute } = useRouter();
|
const { currentRoute } = useRouter();
|
||||||
const { prefixCls } = useDesign('simple-menu');
|
const { prefixCls } = useDesign('simple-menu');
|
||||||
const { items, accordion, mixSider, collapse } = toRefs(props);
|
const { items, accordion, mixSider, collapse } = toRefs(props);
|
||||||
|
|
||||||
const { setOpenKeys, getOpenKeys } = useOpenKeys(
|
const { setOpenKeys, getOpenKeys } = useOpenKeys(
|
||||||
menuState,
|
menuState,
|
||||||
items,
|
items,
|
||||||
@@ -91,6 +91,14 @@
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.items,
|
||||||
|
() => {
|
||||||
|
setOpenKeys(currentRoute.value.path);
|
||||||
|
},
|
||||||
|
{ flush: 'post' }
|
||||||
|
);
|
||||||
|
|
||||||
listenerRouteChange((route) => {
|
listenerRouteChange((route) => {
|
||||||
if (route.name === REDIRECT_NAME) return;
|
if (route.name === REDIRECT_NAME) return;
|
||||||
|
|
||||||
@@ -112,7 +120,6 @@
|
|||||||
menuState.activeName = path;
|
menuState.activeName = path;
|
||||||
|
|
||||||
setOpenKeys(path);
|
setOpenKeys(path);
|
||||||
// if (unref(currentActiveMenu)) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSelect(key: string) {
|
async function handleSelect(key: string) {
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Menu } from '/@/router/types';
|
import type { Menu } from '/@/router/types';
|
||||||
import type { PropType } from 'vue';
|
|
||||||
|
|
||||||
import { defineComponent, computed } from 'vue';
|
import { defineComponent, computed } from 'vue';
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
getCurrentInstance,
|
getCurrentInstance,
|
||||||
provide,
|
provide,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
import { createSimpleRootMenuContext } from './useSimpleMenuContext';
|
import { createSimpleRootMenuContext } from './useSimpleMenuContext';
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
on: {
|
on: {
|
||||||
beforeEnter(el: any) {
|
beforeEnter(el) {
|
||||||
addClass(el, 'collapse-transition');
|
addClass(el, 'collapse-transition');
|
||||||
if (!el.dataset) el.dataset = {};
|
if (!el.dataset) el.dataset = {};
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
el.style.paddingBottom = 0;
|
el.style.paddingBottom = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
enter(el: any) {
|
enter(el) {
|
||||||
el.dataset.oldOverflow = el.style.overflow;
|
el.dataset.oldOverflow = el.style.overflow;
|
||||||
if (el.scrollHeight !== 0) {
|
if (el.scrollHeight !== 0) {
|
||||||
el.style.height = el.scrollHeight + 'px';
|
el.style.height = el.scrollHeight + 'px';
|
||||||
@@ -39,13 +39,13 @@
|
|||||||
el.style.overflow = 'hidden';
|
el.style.overflow = 'hidden';
|
||||||
},
|
},
|
||||||
|
|
||||||
afterEnter(el: any) {
|
afterEnter(el) {
|
||||||
removeClass(el, 'collapse-transition');
|
removeClass(el, 'collapse-transition');
|
||||||
el.style.height = '';
|
el.style.height = '';
|
||||||
el.style.overflow = el.dataset.oldOverflow;
|
el.style.overflow = el.dataset.oldOverflow;
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeLeave(el: any) {
|
beforeLeave(el) {
|
||||||
if (!el.dataset) el.dataset = {};
|
if (!el.dataset) el.dataset = {};
|
||||||
el.dataset.oldPaddingTop = el.style.paddingTop;
|
el.dataset.oldPaddingTop = el.style.paddingTop;
|
||||||
el.dataset.oldPaddingBottom = el.style.paddingBottom;
|
el.dataset.oldPaddingBottom = el.style.paddingBottom;
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
el.style.overflow = 'hidden';
|
el.style.overflow = 'hidden';
|
||||||
},
|
},
|
||||||
|
|
||||||
leave(el: any) {
|
leave(el) {
|
||||||
if (el.scrollHeight !== 0) {
|
if (el.scrollHeight !== 0) {
|
||||||
addClass(el, 'collapse-transition');
|
addClass(el, 'collapse-transition');
|
||||||
el.style.height = 0;
|
el.style.height = 0;
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
afterLeave(el: any) {
|
afterLeave(el) {
|
||||||
removeClass(el, 'collapse-transition');
|
removeClass(el, 'collapse-transition');
|
||||||
el.style.height = '';
|
el.style.height = '';
|
||||||
el.style.overflow = el.dataset.oldOverflow;
|
el.style.overflow = el.dataset.oldOverflow;
|
||||||
|
@@ -78,7 +78,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 = 200;
|
const DELAY = 250;
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SubMenu',
|
name: 'SubMenu',
|
||||||
components: {
|
components: {
|
||||||
|
@@ -51,7 +51,7 @@ export function useMenuItem(instance: ComponentInternalInstance | null) {
|
|||||||
uidList: [],
|
uidList: [],
|
||||||
list: [],
|
list: [],
|
||||||
};
|
};
|
||||||
const ret = [];
|
const ret: any[] = [];
|
||||||
while (parent && parent.type.name !== 'Menu') {
|
while (parent && parent.type.name !== 'Menu') {
|
||||||
if (parent.type.name === 'SubMenu') {
|
if (parent.type.name === 'SubMenu') {
|
||||||
ret.push(parent);
|
ret.push(parent);
|
||||||
|
@@ -8,6 +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';
|
||||||
|
|
||||||
export function useOpenKeys(
|
export function useOpenKeys(
|
||||||
menuState: MenuState,
|
menuState: MenuState,
|
||||||
@@ -15,22 +16,20 @@ export function useOpenKeys(
|
|||||||
accordion: Ref<boolean>,
|
accordion: Ref<boolean>,
|
||||||
mixSider: Ref<boolean>,
|
mixSider: Ref<boolean>,
|
||||||
collapse: Ref<boolean>
|
collapse: Ref<boolean>
|
||||||
// mode: Ref<MenuModeEnum>,
|
|
||||||
) {
|
) {
|
||||||
|
const [debounceSetOpenKeys] = useDebounce(setOpenKeys, 50);
|
||||||
async function setOpenKeys(path: string) {
|
async function setOpenKeys(path: string) {
|
||||||
// if (mode.value === MenuModeEnum.HORIZONTAL) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
const native = !mixSider.value;
|
const native = !mixSider.value;
|
||||||
|
const menuList = toRaw(menus.value);
|
||||||
useTimeoutFn(
|
useTimeoutFn(
|
||||||
() => {
|
() => {
|
||||||
const menuList = toRaw(menus.value);
|
|
||||||
if (menuList?.length === 0) {
|
if (menuList?.length === 0) {
|
||||||
menuState.activeSubMenuNames = [];
|
menuState.activeSubMenuNames = [];
|
||||||
menuState.openNames = [];
|
menuState.openNames = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const keys = getAllParentPath(menuList, path);
|
const keys = getAllParentPath(menuList, path);
|
||||||
|
|
||||||
if (!unref(accordion)) {
|
if (!unref(accordion)) {
|
||||||
menuState.openNames = uniq([...menuState.openNames, ...keys]);
|
menuState.openNames = uniq([...menuState.openNames, ...keys]);
|
||||||
} else {
|
} else {
|
||||||
@@ -38,7 +37,7 @@ export function useOpenKeys(
|
|||||||
}
|
}
|
||||||
menuState.activeSubMenuNames = menuState.openNames;
|
menuState.activeSubMenuNames = menuState.openNames;
|
||||||
},
|
},
|
||||||
16,
|
30,
|
||||||
native
|
native
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -47,5 +46,5 @@ export function useOpenKeys(
|
|||||||
return unref(collapse) ? [] : menuState.openNames;
|
return unref(collapse) ? [] : menuState.openNames;
|
||||||
});
|
});
|
||||||
|
|
||||||
return { setOpenKeys, getOpenKeys };
|
return { setOpenKeys: debounceSetOpenKeys, getOpenKeys };
|
||||||
}
|
}
|
||||||
|
@@ -92,6 +92,20 @@
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getCommonProps = computed(() => {
|
||||||
|
const menus = unref(menusRef);
|
||||||
|
return {
|
||||||
|
menus,
|
||||||
|
beforeClickFn: beforeMenuClickFn,
|
||||||
|
items: menus,
|
||||||
|
theme: unref(getComputedMenuTheme),
|
||||||
|
accordion: unref(getAccordion),
|
||||||
|
collapse: unref(getCollapsed),
|
||||||
|
collapsedShowTitle: unref(getCollapsedShowTitle),
|
||||||
|
onMenuClick: handleMenuClick,
|
||||||
|
};
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* click menu
|
* click menu
|
||||||
* @param menu
|
* @param menu
|
||||||
@@ -126,31 +140,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderMenu() {
|
function renderMenu() {
|
||||||
const menus = unref(menusRef);
|
const { menus, ...menuProps } = unref(getCommonProps);
|
||||||
// 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
|
<SimpleMenu {...menuProps} items={menus} />
|
||||||
beforeClickFn={beforeMenuClickFn}
|
|
||||||
items={menus}
|
|
||||||
theme={unref(getComputedMenuTheme)}
|
|
||||||
accordion={unref(getAccordion)}
|
|
||||||
collapse={unref(getCollapsed)}
|
|
||||||
collapsedShowTitle={unref(getCollapsedShowTitle)}
|
|
||||||
onMenuClick={handleMenuClick}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<BasicMenu
|
<BasicMenu
|
||||||
beforeClickFn={beforeMenuClickFn}
|
{...menuProps}
|
||||||
isHorizontal={props.isHorizontal}
|
isHorizontal={props.isHorizontal}
|
||||||
type={unref(getMenuType)}
|
type={unref(getMenuType)}
|
||||||
collapsedShowTitle={unref(getCollapsedShowTitle)}
|
|
||||||
showLogo={unref(getIsShowLogo)}
|
showLogo={unref(getIsShowLogo)}
|
||||||
mode={unref(getComputedMenuMode)}
|
mode={unref(getComputedMenuMode)}
|
||||||
theme={unref(getComputedMenuTheme)}
|
|
||||||
items={menus}
|
items={menus}
|
||||||
accordion={unref(getAccordion)}
|
|
||||||
onMenuClick={handleMenuClick}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -65,10 +65,13 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// split Menu changes
|
// split Menu changes
|
||||||
watch([() => getSplit.value], () => {
|
watch(
|
||||||
if (unref(splitNotLeft)) return;
|
() => getSplit.value,
|
||||||
genMenus();
|
() => {
|
||||||
});
|
if (unref(splitNotLeft)) return;
|
||||||
|
genMenus();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Handle left menu split
|
// Handle left menu split
|
||||||
async function handleSplitLeftMenu(parentPath: string) {
|
async function handleSplitLeftMenu(parentPath: string) {
|
||||||
|
5
types/global.d.ts
vendored
5
types/global.d.ts
vendored
@@ -3,13 +3,18 @@ import type {
|
|||||||
VNode,
|
VNode,
|
||||||
ComponentPublicInstance,
|
ComponentPublicInstance,
|
||||||
FunctionalComponent,
|
FunctionalComponent,
|
||||||
|
PropType as VuePropType,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// declare interface Window {
|
// declare interface Window {
|
||||||
// Global vue app instance
|
// Global vue app instance
|
||||||
// __APP__: App<Element>;
|
// __APP__: App<Element>;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// vue
|
||||||
|
declare type PropType<T> = VuePropType<T>;
|
||||||
|
|
||||||
export type Writable<T> = {
|
export type Writable<T> = {
|
||||||
-readonly [P in keyof T]: T[P];
|
-readonly [P in keyof T]: T[P];
|
||||||
};
|
};
|
||||||
|
@@ -2284,10 +2284,10 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-convert "^2.0.1"
|
color-convert "^2.0.1"
|
||||||
|
|
||||||
ant-design-vue@2.1.0:
|
ant-design-vue@2.1.1:
|
||||||
version "2.1.0"
|
version "2.1.1"
|
||||||
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.0.tgz#2489240f638f39874281e237544b857ebce52d18"
|
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.1.tgz#5c2f3d86177e197f6dbb167f691a9d10104e61c3"
|
||||||
integrity sha512-wzgwHRuwZrSvixccNlvas2gTWBkmfMrifbSsP+ga8VV6F0C6DdlimeFo+P99AxnVgpNVk8OUq9RVDQjb1UGk6g==
|
integrity sha512-ohTEIBFRkODRTFXRHeizL/uKNOZY5+4r2y/GXiKEdvrxiTRgHgDNMWKsncG/+G6MXxOIe2Reg+r8jHS8nGDqtQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ant-design-vue/use" "^0.0.1-0"
|
"@ant-design-vue/use" "^0.0.1-0"
|
||||||
"@ant-design/icons-vue" "^6.0.0"
|
"@ant-design/icons-vue" "^6.0.0"
|
||||||
|
Reference in New Issue
Block a user