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
@@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
34 | "@iconify/iconify": "^2.0.0-rc.6", | 34 | "@iconify/iconify": "^2.0.0-rc.6", |
35 | "@vueuse/core": "^4.6.2", | 35 | "@vueuse/core": "^4.6.2", |
36 | "@zxcvbn-ts/core": "^0.3.0", | 36 | "@zxcvbn-ts/core": "^0.3.0", |
37 | - "ant-design-vue": "2.1.0", | 37 | + "ant-design-vue": "2.1.1", |
38 | "apexcharts": "^3.26.0", | 38 | "apexcharts": "^3.26.0", |
39 | "axios": "^0.21.1", | 39 | "axios": "^0.21.1", |
40 | "crypto-js": "^4.0.0", | 40 | "crypto-js": "^4.0.0", |
src/components/SimpleMenu/src/SimpleMenu.vue
@@ -18,7 +18,6 @@ | @@ -18,7 +18,6 @@ | ||
18 | </Menu> | 18 | </Menu> |
19 | </template> | 19 | </template> |
20 | <script lang="ts"> | 20 | <script lang="ts"> |
21 | - import type { PropType } from 'vue'; | ||
22 | import type { MenuState } from './types'; | 21 | import type { MenuState } from './types'; |
23 | import type { Menu as MenuType } from '/@/router/types'; | 22 | import type { Menu as MenuType } from '/@/router/types'; |
24 | 23 | ||
@@ -69,6 +68,7 @@ | @@ -69,6 +68,7 @@ | ||
69 | const { currentRoute } = useRouter(); | 68 | const { currentRoute } = useRouter(); |
70 | const { prefixCls } = useDesign('simple-menu'); | 69 | const { prefixCls } = useDesign('simple-menu'); |
71 | const { items, accordion, mixSider, collapse } = toRefs(props); | 70 | const { items, accordion, mixSider, collapse } = toRefs(props); |
71 | + | ||
72 | const { setOpenKeys, getOpenKeys } = useOpenKeys( | 72 | const { setOpenKeys, getOpenKeys } = useOpenKeys( |
73 | menuState, | 73 | menuState, |
74 | items, | 74 | items, |
@@ -91,6 +91,14 @@ | @@ -91,6 +91,14 @@ | ||
91 | { immediate: true } | 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 | listenerRouteChange((route) => { | 102 | listenerRouteChange((route) => { |
95 | if (route.name === REDIRECT_NAME) return; | 103 | if (route.name === REDIRECT_NAME) return; |
96 | 104 | ||
@@ -112,7 +120,6 @@ | @@ -112,7 +120,6 @@ | ||
112 | menuState.activeName = path; | 120 | menuState.activeName = path; |
113 | 121 | ||
114 | setOpenKeys(path); | 122 | setOpenKeys(path); |
115 | - // if (unref(currentActiveMenu)) return; | ||
116 | } | 123 | } |
117 | 124 | ||
118 | async function handleSelect(key: string) { | 125 | async function handleSelect(key: string) { |
src/components/SimpleMenu/src/SimpleMenuTag.vue
@@ -3,7 +3,6 @@ | @@ -3,7 +3,6 @@ | ||
3 | </template> | 3 | </template> |
4 | <script lang="ts"> | 4 | <script lang="ts"> |
5 | import type { Menu } from '/@/router/types'; | 5 | import type { Menu } from '/@/router/types'; |
6 | - import type { PropType } from 'vue'; | ||
7 | 6 | ||
8 | import { defineComponent, computed } from 'vue'; | 7 | import { defineComponent, computed } from 'vue'; |
9 | 8 |
src/components/SimpleMenu/src/components/Menu.vue
@@ -18,6 +18,7 @@ | @@ -18,6 +18,7 @@ | ||
18 | getCurrentInstance, | 18 | getCurrentInstance, |
19 | provide, | 19 | provide, |
20 | } from 'vue'; | 20 | } from 'vue'; |
21 | + | ||
21 | import { useDesign } from '/@/hooks/web/useDesign'; | 22 | import { useDesign } from '/@/hooks/web/useDesign'; |
22 | import { propTypes } from '/@/utils/propTypes'; | 23 | import { propTypes } from '/@/utils/propTypes'; |
23 | import { createSimpleRootMenuContext } from './useSimpleMenuContext'; | 24 | import { createSimpleRootMenuContext } from './useSimpleMenuContext'; |
src/components/SimpleMenu/src/components/MenuCollapseTransition.vue
@@ -12,7 +12,7 @@ | @@ -12,7 +12,7 @@ | ||
12 | setup() { | 12 | setup() { |
13 | return { | 13 | return { |
14 | on: { | 14 | on: { |
15 | - beforeEnter(el: any) { | 15 | + beforeEnter(el) { |
16 | addClass(el, 'collapse-transition'); | 16 | addClass(el, 'collapse-transition'); |
17 | if (!el.dataset) el.dataset = {}; | 17 | if (!el.dataset) el.dataset = {}; |
18 | 18 | ||
@@ -24,7 +24,7 @@ | @@ -24,7 +24,7 @@ | ||
24 | el.style.paddingBottom = 0; | 24 | el.style.paddingBottom = 0; |
25 | }, | 25 | }, |
26 | 26 | ||
27 | - enter(el: any) { | 27 | + enter(el) { |
28 | el.dataset.oldOverflow = el.style.overflow; | 28 | el.dataset.oldOverflow = el.style.overflow; |
29 | if (el.scrollHeight !== 0) { | 29 | if (el.scrollHeight !== 0) { |
30 | el.style.height = el.scrollHeight + 'px'; | 30 | el.style.height = el.scrollHeight + 'px'; |
@@ -39,13 +39,13 @@ | @@ -39,13 +39,13 @@ | ||
39 | el.style.overflow = 'hidden'; | 39 | el.style.overflow = 'hidden'; |
40 | }, | 40 | }, |
41 | 41 | ||
42 | - afterEnter(el: any) { | 42 | + afterEnter(el) { |
43 | removeClass(el, 'collapse-transition'); | 43 | removeClass(el, 'collapse-transition'); |
44 | el.style.height = ''; | 44 | el.style.height = ''; |
45 | el.style.overflow = el.dataset.oldOverflow; | 45 | el.style.overflow = el.dataset.oldOverflow; |
46 | }, | 46 | }, |
47 | 47 | ||
48 | - beforeLeave(el: any) { | 48 | + beforeLeave(el) { |
49 | if (!el.dataset) el.dataset = {}; | 49 | if (!el.dataset) el.dataset = {}; |
50 | el.dataset.oldPaddingTop = el.style.paddingTop; | 50 | el.dataset.oldPaddingTop = el.style.paddingTop; |
51 | el.dataset.oldPaddingBottom = el.style.paddingBottom; | 51 | el.dataset.oldPaddingBottom = el.style.paddingBottom; |
@@ -55,7 +55,7 @@ | @@ -55,7 +55,7 @@ | ||
55 | el.style.overflow = 'hidden'; | 55 | el.style.overflow = 'hidden'; |
56 | }, | 56 | }, |
57 | 57 | ||
58 | - leave(el: any) { | 58 | + leave(el) { |
59 | if (el.scrollHeight !== 0) { | 59 | if (el.scrollHeight !== 0) { |
60 | addClass(el, 'collapse-transition'); | 60 | addClass(el, 'collapse-transition'); |
61 | el.style.height = 0; | 61 | el.style.height = 0; |
@@ -64,7 +64,7 @@ | @@ -64,7 +64,7 @@ | ||
64 | } | 64 | } |
65 | }, | 65 | }, |
66 | 66 | ||
67 | - afterLeave(el: any) { | 67 | + afterLeave(el) { |
68 | removeClass(el, 'collapse-transition'); | 68 | removeClass(el, 'collapse-transition'); |
69 | el.style.height = ''; | 69 | el.style.height = ''; |
70 | el.style.overflow = el.dataset.oldOverflow; | 70 | el.style.overflow = el.dataset.oldOverflow; |
src/components/SimpleMenu/src/components/SubMenuItem.vue
@@ -78,7 +78,7 @@ | @@ -78,7 +78,7 @@ | ||
78 | import { isBoolean, isObject } from '/@/utils/is'; | 78 | import { isBoolean, isObject } from '/@/utils/is'; |
79 | import Mitt from '/@/utils/mitt'; | 79 | import Mitt from '/@/utils/mitt'; |
80 | 80 | ||
81 | - const DELAY = 200; | 81 | + const DELAY = 250; |
82 | export default defineComponent({ | 82 | export default defineComponent({ |
83 | name: 'SubMenu', | 83 | name: 'SubMenu', |
84 | components: { | 84 | components: { |
src/components/SimpleMenu/src/components/useMenu.ts
@@ -51,7 +51,7 @@ export function useMenuItem(instance: ComponentInternalInstance | null) { | @@ -51,7 +51,7 @@ export function useMenuItem(instance: ComponentInternalInstance | null) { | ||
51 | uidList: [], | 51 | uidList: [], |
52 | list: [], | 52 | list: [], |
53 | }; | 53 | }; |
54 | - const ret = []; | 54 | + const ret: any[] = []; |
55 | while (parent && parent.type.name !== 'Menu') { | 55 | while (parent && parent.type.name !== 'Menu') { |
56 | if (parent.type.name === 'SubMenu') { | 56 | if (parent.type.name === 'SubMenu') { |
57 | ret.push(parent); | 57 | ret.push(parent); |
src/components/SimpleMenu/src/useOpenKeys.ts
@@ -8,6 +8,7 @@ import { uniq } from 'lodash-es'; | @@ -8,6 +8,7 @@ import { uniq } from 'lodash-es'; | ||
8 | import { getAllParentPath } from '/@/router/helper/menuHelper'; | 8 | import { getAllParentPath } from '/@/router/helper/menuHelper'; |
9 | 9 | ||
10 | import { useTimeoutFn } from '/@/hooks/core/useTimeout'; | 10 | import { useTimeoutFn } from '/@/hooks/core/useTimeout'; |
11 | +import { useDebounce } from '../../../hooks/core/useDebounce'; | ||
11 | 12 | ||
12 | export function useOpenKeys( | 13 | export function useOpenKeys( |
13 | menuState: MenuState, | 14 | menuState: MenuState, |
@@ -15,22 +16,20 @@ export function useOpenKeys( | @@ -15,22 +16,20 @@ export function useOpenKeys( | ||
15 | accordion: Ref<boolean>, | 16 | accordion: Ref<boolean>, |
16 | mixSider: Ref<boolean>, | 17 | mixSider: Ref<boolean>, |
17 | collapse: Ref<boolean> | 18 | collapse: Ref<boolean> |
18 | - // mode: Ref<MenuModeEnum>, | ||
19 | ) { | 19 | ) { |
20 | + const [debounceSetOpenKeys] = useDebounce(setOpenKeys, 50); | ||
20 | async function setOpenKeys(path: string) { | 21 | async function setOpenKeys(path: string) { |
21 | - // if (mode.value === MenuModeEnum.HORIZONTAL) { | ||
22 | - // return; | ||
23 | - // } | ||
24 | const native = !mixSider.value; | 22 | const native = !mixSider.value; |
23 | + const menuList = toRaw(menus.value); | ||
25 | useTimeoutFn( | 24 | useTimeoutFn( |
26 | () => { | 25 | () => { |
27 | - const menuList = toRaw(menus.value); | ||
28 | if (menuList?.length === 0) { | 26 | if (menuList?.length === 0) { |
29 | menuState.activeSubMenuNames = []; | 27 | menuState.activeSubMenuNames = []; |
30 | menuState.openNames = []; | 28 | menuState.openNames = []; |
31 | return; | 29 | return; |
32 | } | 30 | } |
33 | const keys = getAllParentPath(menuList, path); | 31 | const keys = getAllParentPath(menuList, path); |
32 | + | ||
34 | if (!unref(accordion)) { | 33 | if (!unref(accordion)) { |
35 | menuState.openNames = uniq([...menuState.openNames, ...keys]); | 34 | menuState.openNames = uniq([...menuState.openNames, ...keys]); |
36 | } else { | 35 | } else { |
@@ -38,7 +37,7 @@ export function useOpenKeys( | @@ -38,7 +37,7 @@ export function useOpenKeys( | ||
38 | } | 37 | } |
39 | menuState.activeSubMenuNames = menuState.openNames; | 38 | menuState.activeSubMenuNames = menuState.openNames; |
40 | }, | 39 | }, |
41 | - 16, | 40 | + 30, |
42 | native | 41 | native |
43 | ); | 42 | ); |
44 | } | 43 | } |
@@ -47,5 +46,5 @@ export function useOpenKeys( | @@ -47,5 +46,5 @@ export function useOpenKeys( | ||
47 | return unref(collapse) ? [] : menuState.openNames; | 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,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 | * click menu | 110 | * click menu |
97 | * @param menu | 111 | * @param menu |
@@ -126,31 +140,19 @@ | @@ -126,31 +140,19 @@ | ||
126 | } | 140 | } |
127 | 141 | ||
128 | function renderMenu() { | 142 | function renderMenu() { |
129 | - const menus = unref(menusRef); | 143 | + const { menus, ...menuProps } = unref(getCommonProps); |
130 | // console.log(menus); | 144 | // console.log(menus); |
131 | if (!menus || !menus.length) return null; | 145 | if (!menus || !menus.length) return null; |
132 | return !props.isHorizontal ? ( | 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 | <BasicMenu | 149 | <BasicMenu |
144 | - beforeClickFn={beforeMenuClickFn} | 150 | + {...menuProps} |
145 | isHorizontal={props.isHorizontal} | 151 | isHorizontal={props.isHorizontal} |
146 | type={unref(getMenuType)} | 152 | type={unref(getMenuType)} |
147 | - collapsedShowTitle={unref(getCollapsedShowTitle)} | ||
148 | showLogo={unref(getIsShowLogo)} | 153 | showLogo={unref(getIsShowLogo)} |
149 | mode={unref(getComputedMenuMode)} | 154 | mode={unref(getComputedMenuMode)} |
150 | - theme={unref(getComputedMenuTheme)} | ||
151 | items={menus} | 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,10 +65,13 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) { | ||
65 | ); | 65 | ); |
66 | 66 | ||
67 | // split Menu changes | 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 | // Handle left menu split | 76 | // Handle left menu split |
74 | async function handleSplitLeftMenu(parentPath: string) { | 77 | async function handleSplitLeftMenu(parentPath: string) { |
types/global.d.ts
@@ -3,13 +3,18 @@ import type { | @@ -3,13 +3,18 @@ import type { | ||
3 | VNode, | 3 | VNode, |
4 | ComponentPublicInstance, | 4 | ComponentPublicInstance, |
5 | FunctionalComponent, | 5 | FunctionalComponent, |
6 | + PropType as VuePropType, | ||
6 | } from 'vue'; | 7 | } from 'vue'; |
8 | + | ||
7 | declare global { | 9 | declare global { |
8 | // declare interface Window { | 10 | // declare interface Window { |
9 | // Global vue app instance | 11 | // Global vue app instance |
10 | // __APP__: App<Element>; | 12 | // __APP__: App<Element>; |
11 | // } | 13 | // } |
12 | 14 | ||
15 | + // vue | ||
16 | + declare type PropType<T> = VuePropType<T>; | ||
17 | + | ||
13 | export type Writable<T> = { | 18 | export type Writable<T> = { |
14 | -readonly [P in keyof T]: T[P]; | 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,10 +2284,10 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: | ||
2284 | dependencies: | 2284 | dependencies: |
2285 | color-convert "^2.0.1" | 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 | dependencies: | 2291 | dependencies: |
2292 | "@ant-design-vue/use" "^0.0.1-0" | 2292 | "@ant-design-vue/use" "^0.0.1-0" |
2293 | "@ant-design/icons-vue" "^6.0.0" | 2293 | "@ant-design/icons-vue" "^6.0.0" |