Commit bb67692cfdd5089f0f1d60d4a36b52592db22dde
1 parent
0b66360c
fix(menu): ensure the menu is activated correctly,fix #432
Showing
12 changed files
with
58 additions
and
42 deletions
package.json
src/components/SimpleMenu/src/SimpleMenu.vue
... | ... | @@ -18,7 +18,6 @@ |
18 | 18 | </Menu> |
19 | 19 | </template> |
20 | 20 | <script lang="ts"> |
21 | - import type { PropType } from 'vue'; | |
22 | 21 | import type { MenuState } from './types'; |
23 | 22 | import type { Menu as MenuType } from '/@/router/types'; |
24 | 23 | |
... | ... | @@ -69,6 +68,7 @@ |
69 | 68 | const { currentRoute } = useRouter(); |
70 | 69 | const { prefixCls } = useDesign('simple-menu'); |
71 | 70 | const { items, accordion, mixSider, collapse } = toRefs(props); |
71 | + | |
72 | 72 | const { setOpenKeys, getOpenKeys } = useOpenKeys( |
73 | 73 | menuState, |
74 | 74 | items, |
... | ... | @@ -91,6 +91,14 @@ |
91 | 91 | { immediate: true } |
92 | 92 | ); |
93 | 93 | |
94 | + watch( | |
95 | + () => props.items, | |
96 | + () => { | |
97 | + setOpenKeys(currentRoute.value.path); | |
98 | + }, | |
99 | + { flush: 'post' } | |
100 | + ); | |
101 | + | |
94 | 102 | listenerRouteChange((route) => { |
95 | 103 | if (route.name === REDIRECT_NAME) return; |
96 | 104 | |
... | ... | @@ -112,7 +120,6 @@ |
112 | 120 | menuState.activeName = path; |
113 | 121 | |
114 | 122 | setOpenKeys(path); |
115 | - // if (unref(currentActiveMenu)) return; | |
116 | 123 | } |
117 | 124 | |
118 | 125 | async function handleSelect(key: string) { | ... | ... |
src/components/SimpleMenu/src/SimpleMenuTag.vue
src/components/SimpleMenu/src/components/Menu.vue
src/components/SimpleMenu/src/components/MenuCollapseTransition.vue
... | ... | @@ -12,7 +12,7 @@ |
12 | 12 | setup() { |
13 | 13 | return { |
14 | 14 | on: { |
15 | - beforeEnter(el: any) { | |
15 | + beforeEnter(el) { | |
16 | 16 | addClass(el, 'collapse-transition'); |
17 | 17 | if (!el.dataset) el.dataset = {}; |
18 | 18 | |
... | ... | @@ -24,7 +24,7 @@ |
24 | 24 | el.style.paddingBottom = 0; |
25 | 25 | }, |
26 | 26 | |
27 | - enter(el: any) { | |
27 | + enter(el) { | |
28 | 28 | el.dataset.oldOverflow = el.style.overflow; |
29 | 29 | if (el.scrollHeight !== 0) { |
30 | 30 | el.style.height = el.scrollHeight + 'px'; |
... | ... | @@ -39,13 +39,13 @@ |
39 | 39 | el.style.overflow = 'hidden'; |
40 | 40 | }, |
41 | 41 | |
42 | - afterEnter(el: any) { | |
42 | + afterEnter(el) { | |
43 | 43 | removeClass(el, 'collapse-transition'); |
44 | 44 | el.style.height = ''; |
45 | 45 | el.style.overflow = el.dataset.oldOverflow; |
46 | 46 | }, |
47 | 47 | |
48 | - beforeLeave(el: any) { | |
48 | + beforeLeave(el) { | |
49 | 49 | if (!el.dataset) el.dataset = {}; |
50 | 50 | el.dataset.oldPaddingTop = el.style.paddingTop; |
51 | 51 | el.dataset.oldPaddingBottom = el.style.paddingBottom; |
... | ... | @@ -55,7 +55,7 @@ |
55 | 55 | el.style.overflow = 'hidden'; |
56 | 56 | }, |
57 | 57 | |
58 | - leave(el: any) { | |
58 | + leave(el) { | |
59 | 59 | if (el.scrollHeight !== 0) { |
60 | 60 | addClass(el, 'collapse-transition'); |
61 | 61 | el.style.height = 0; |
... | ... | @@ -64,7 +64,7 @@ |
64 | 64 | } |
65 | 65 | }, |
66 | 66 | |
67 | - afterLeave(el: any) { | |
67 | + afterLeave(el) { | |
68 | 68 | removeClass(el, 'collapse-transition'); |
69 | 69 | el.style.height = ''; |
70 | 70 | el.style.overflow = el.dataset.oldOverflow; | ... | ... |
src/components/SimpleMenu/src/components/SubMenuItem.vue
src/components/SimpleMenu/src/components/useMenu.ts
... | ... | @@ -51,7 +51,7 @@ export function useMenuItem(instance: ComponentInternalInstance | null) { |
51 | 51 | uidList: [], |
52 | 52 | list: [], |
53 | 53 | }; |
54 | - const ret = []; | |
54 | + const ret: any[] = []; | |
55 | 55 | while (parent && parent.type.name !== 'Menu') { |
56 | 56 | if (parent.type.name === 'SubMenu') { |
57 | 57 | ret.push(parent); | ... | ... |
src/components/SimpleMenu/src/useOpenKeys.ts
... | ... | @@ -8,6 +8,7 @@ import { uniq } from 'lodash-es'; |
8 | 8 | import { getAllParentPath } from '/@/router/helper/menuHelper'; |
9 | 9 | |
10 | 10 | import { useTimeoutFn } from '/@/hooks/core/useTimeout'; |
11 | +import { useDebounce } from '../../../hooks/core/useDebounce'; | |
11 | 12 | |
12 | 13 | export function useOpenKeys( |
13 | 14 | menuState: MenuState, |
... | ... | @@ -15,22 +16,20 @@ export function useOpenKeys( |
15 | 16 | accordion: Ref<boolean>, |
16 | 17 | mixSider: Ref<boolean>, |
17 | 18 | collapse: Ref<boolean> |
18 | - // mode: Ref<MenuModeEnum>, | |
19 | 19 | ) { |
20 | + const [debounceSetOpenKeys] = useDebounce(setOpenKeys, 50); | |
20 | 21 | async function setOpenKeys(path: string) { |
21 | - // if (mode.value === MenuModeEnum.HORIZONTAL) { | |
22 | - // return; | |
23 | - // } | |
24 | 22 | const native = !mixSider.value; |
23 | + const menuList = toRaw(menus.value); | |
25 | 24 | useTimeoutFn( |
26 | 25 | () => { |
27 | - const menuList = toRaw(menus.value); | |
28 | 26 | if (menuList?.length === 0) { |
29 | 27 | menuState.activeSubMenuNames = []; |
30 | 28 | menuState.openNames = []; |
31 | 29 | return; |
32 | 30 | } |
33 | 31 | const keys = getAllParentPath(menuList, path); |
32 | + | |
34 | 33 | if (!unref(accordion)) { |
35 | 34 | menuState.openNames = uniq([...menuState.openNames, ...keys]); |
36 | 35 | } else { |
... | ... | @@ -38,7 +37,7 @@ export function useOpenKeys( |
38 | 37 | } |
39 | 38 | menuState.activeSubMenuNames = menuState.openNames; |
40 | 39 | }, |
41 | - 16, | |
40 | + 30, | |
42 | 41 | native |
43 | 42 | ); |
44 | 43 | } |
... | ... | @@ -47,5 +46,5 @@ export function useOpenKeys( |
47 | 46 | return unref(collapse) ? [] : menuState.openNames; |
48 | 47 | }); |
49 | 48 | |
50 | - return { setOpenKeys, getOpenKeys }; | |
49 | + return { setOpenKeys: debounceSetOpenKeys, getOpenKeys }; | |
51 | 50 | } | ... | ... |
src/layouts/default/menu/index.vue
... | ... | @@ -92,6 +92,20 @@ |
92 | 92 | }, |
93 | 93 | ]; |
94 | 94 | }); |
95 | + | |
96 | + const getCommonProps = computed(() => { | |
97 | + const menus = unref(menusRef); | |
98 | + return { | |
99 | + menus, | |
100 | + beforeClickFn: beforeMenuClickFn, | |
101 | + items: menus, | |
102 | + theme: unref(getComputedMenuTheme), | |
103 | + accordion: unref(getAccordion), | |
104 | + collapse: unref(getCollapsed), | |
105 | + collapsedShowTitle: unref(getCollapsedShowTitle), | |
106 | + onMenuClick: handleMenuClick, | |
107 | + }; | |
108 | + }); | |
95 | 109 | /** |
96 | 110 | * click menu |
97 | 111 | * @param menu |
... | ... | @@ -126,31 +140,19 @@ |
126 | 140 | } |
127 | 141 | |
128 | 142 | function renderMenu() { |
129 | - const menus = unref(menusRef); | |
143 | + const { menus, ...menuProps } = unref(getCommonProps); | |
130 | 144 | // console.log(menus); |
131 | 145 | if (!menus || !menus.length) return null; |
132 | 146 | return !props.isHorizontal ? ( |
133 | - <SimpleMenu | |
134 | - beforeClickFn={beforeMenuClickFn} | |
135 | - items={menus} | |
136 | - theme={unref(getComputedMenuTheme)} | |
137 | - accordion={unref(getAccordion)} | |
138 | - collapse={unref(getCollapsed)} | |
139 | - collapsedShowTitle={unref(getCollapsedShowTitle)} | |
140 | - onMenuClick={handleMenuClick} | |
141 | - /> | |
147 | + <SimpleMenu {...menuProps} items={menus} /> | |
142 | 148 | ) : ( |
143 | 149 | <BasicMenu |
144 | - beforeClickFn={beforeMenuClickFn} | |
150 | + {...menuProps} | |
145 | 151 | isHorizontal={props.isHorizontal} |
146 | 152 | type={unref(getMenuType)} |
147 | - collapsedShowTitle={unref(getCollapsedShowTitle)} | |
148 | 153 | showLogo={unref(getIsShowLogo)} |
149 | 154 | mode={unref(getComputedMenuMode)} |
150 | - theme={unref(getComputedMenuTheme)} | |
151 | 155 | items={menus} |
152 | - accordion={unref(getAccordion)} | |
153 | - onMenuClick={handleMenuClick} | |
154 | 156 | /> |
155 | 157 | ); |
156 | 158 | } | ... | ... |
src/layouts/default/menu/useLayoutMenu.ts
... | ... | @@ -65,10 +65,13 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) { |
65 | 65 | ); |
66 | 66 | |
67 | 67 | // split Menu changes |
68 | - watch([() => getSplit.value], () => { | |
69 | - if (unref(splitNotLeft)) return; | |
70 | - genMenus(); | |
71 | - }); | |
68 | + watch( | |
69 | + () => getSplit.value, | |
70 | + () => { | |
71 | + if (unref(splitNotLeft)) return; | |
72 | + genMenus(); | |
73 | + } | |
74 | + ); | |
72 | 75 | |
73 | 76 | // Handle left menu split |
74 | 77 | async function handleSplitLeftMenu(parentPath: string) { | ... | ... |
types/global.d.ts
... | ... | @@ -3,13 +3,18 @@ import type { |
3 | 3 | VNode, |
4 | 4 | ComponentPublicInstance, |
5 | 5 | FunctionalComponent, |
6 | + PropType as VuePropType, | |
6 | 7 | } from 'vue'; |
8 | + | |
7 | 9 | declare global { |
8 | 10 | // declare interface Window { |
9 | 11 | // Global vue app instance |
10 | 12 | // __APP__: App<Element>; |
11 | 13 | // } |
12 | 14 | |
15 | + // vue | |
16 | + declare type PropType<T> = VuePropType<T>; | |
17 | + | |
13 | 18 | export type Writable<T> = { |
14 | 19 | -readonly [P in keyof T]: T[P]; |
15 | 20 | }; | ... | ... |
yarn.lock
... | ... | @@ -2284,10 +2284,10 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: |
2284 | 2284 | dependencies: |
2285 | 2285 | color-convert "^2.0.1" |
2286 | 2286 | |
2287 | -ant-design-vue@2.1.0: | |
2288 | - version "2.1.0" | |
2289 | - resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.0.tgz#2489240f638f39874281e237544b857ebce52d18" | |
2290 | - integrity sha512-wzgwHRuwZrSvixccNlvas2gTWBkmfMrifbSsP+ga8VV6F0C6DdlimeFo+P99AxnVgpNVk8OUq9RVDQjb1UGk6g== | |
2287 | +ant-design-vue@2.1.1: | |
2288 | + version "2.1.1" | |
2289 | + resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.1.tgz#5c2f3d86177e197f6dbb167f691a9d10104e61c3" | |
2290 | + integrity sha512-ohTEIBFRkODRTFXRHeizL/uKNOZY5+4r2y/GXiKEdvrxiTRgHgDNMWKsncG/+G6MXxOIe2Reg+r8jHS8nGDqtQ== | |
2291 | 2291 | dependencies: |
2292 | 2292 | "@ant-design-vue/use" "^0.0.1-0" |
2293 | 2293 | "@ant-design/icons-vue" "^6.0.0" | ... | ... |