diff --git a/packages/devui-vue/devui/menu/src/components/menu-item/menu-item.tsx b/packages/devui-vue/devui/menu/src/components/menu-item/menu-item.tsx index d8818ffae9..8de5d3bd80 100644 --- a/packages/devui-vue/devui/menu/src/components/menu-item/menu-item.tsx +++ b/packages/devui-vue/devui/menu/src/components/menu-item/menu-item.tsx @@ -5,6 +5,7 @@ import { initSelect, addActiveParent, changeRoute } from './use-menu-item'; import { useClick } from '../../composables/use-click'; import { useNamespace } from '../../../../shared/hooks/use-namespace'; import { Router } from 'vue-router'; +import { Store } from '../../composables/use-store'; const ns = useNamespace('menu'); @@ -21,6 +22,7 @@ export default defineComponent({ setup(props: MenuItemProps, ctx) { const instance = getCurrentInstance(); const key = String(instance?.vnode.key); + const menuStore = inject('menuStore') as Store; const mode = inject('mode') as Ref<'vertical' | 'horizontal'>; const multiple = inject('multiple') as boolean; const indent = inject('defaultIndent'); @@ -38,6 +40,9 @@ export default defineComponent({ [menuItemSelect]: isSelect.value, [menuItemDisabled]: disabled.value, })); + menuStore.on('menuItem:clear:select', ()=>{ + isSelect.value = false; + }); const onClick = (e: MouseEvent) => { e.stopPropagation(); const ele = e.currentTarget as HTMLElement; @@ -45,19 +50,20 @@ export default defineComponent({ props.disabled && e.preventDefault(); if (!props.disabled) { if (!multiple) { + menuStore.emit('menuItem:clear:select'); clearSelect(ele, e, mode.value === 'horizontal'); if (mode.value === 'horizontal') { useClick(e as clickEvent); - } else { - ele.classList.add(menuItemSelect); } + isSelect.value = true; changeRouteResult = changeRoute(props, router, useRouter, key); } else { if (ele.classList.contains(menuItemSelect)) { - ele.classList.remove(menuItemSelect); rootMenuEmit('deselect', { type: 'deselect', key, el: ele, e }); + isSelect.value = false; return; } else { + isSelect.value = true; ele.classList.add(menuItemSelect); } } diff --git a/packages/devui-vue/devui/menu/src/composables/use-store.ts b/packages/devui-vue/devui/menu/src/composables/use-store.ts new file mode 100644 index 0000000000..9fcca009d1 --- /dev/null +++ b/packages/devui-vue/devui/menu/src/composables/use-store.ts @@ -0,0 +1,38 @@ +interface record { + [x: string]: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [eventName: string]: ((...args: any[]) => void)[]; + }; +} +const recordTable: record = {}; +export class Store{ + private rootMenuName: string; + constructor(rootName: string){ + this.rootMenuName = rootName; + } + // Unified use [menu,menuItem,subMenu]:state:action name + // eslint-disable-next-line @typescript-eslint/no-explicit-any + on(eventName: string, fn: (...args: any[]) => void): void{ + if (!recordTable?.[this.rootMenuName]?.[eventName]){ + Reflect.set(recordTable[this.rootMenuName],eventName, []); + } + recordTable[this.rootMenuName][eventName].push(fn); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + emit(eventName: string, ...args: any[]): void{ + recordTable[this.rootMenuName][eventName].forEach((fn)=>fn(...args)); + } + off(eventName: string, fn: (...args: []) => void): void{ + const idx = recordTable[this.rootMenuName][eventName].indexOf(fn); + if (idx >= 0) { + recordTable[this.rootMenuName][eventName].splice(idx, 1); + } + } +} + +export function useStore(rootName: string): Store{ + if (!recordTable[rootName]){ + Reflect.set(recordTable, rootName, {}); + } + return new Store(rootName); +} diff --git a/packages/devui-vue/devui/menu/src/menu.tsx b/packages/devui-vue/devui/menu/src/menu.tsx index 2df662622e..cbd5390a29 100644 --- a/packages/devui-vue/devui/menu/src/menu.tsx +++ b/packages/devui-vue/devui/menu/src/menu.tsx @@ -6,6 +6,8 @@ import { setDefaultIndent } from './composables/use-layer-operate'; import SubMenu from './components/sub-menu/sub-menu'; import { useNamespace } from '../../shared/hooks/use-namespace'; import { useShowSubMenu } from './components/sub-menu/use-sub-menu'; +import { randomId } from '../../shared/utils'; +import { useStore } from './composables/use-store'; export default defineComponent({ name: 'DMenu', @@ -14,6 +16,11 @@ export default defineComponent({ setup(props: MenuProps, ctx) { const ns = useNamespace('menu'); const {openKeys, mode, collapsed} = toRefs(props); + // This ID is only for internal use. So we unwanted use reactivity + const menuId = randomId(16); + // register menu to recordTable. + const store = useStore(menuId); + provide('menuStore', store); provide('isCollapsed', collapsed); provide('defaultIndent', props['indentSize']); provide('multiple', props['multiple']);