From c3d1151f633d3c3580f621da7ba396beb3c5086b Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Tue, 9 Aug 2022 14:03:30 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(menu):=20=E8=A7=A3=E5=86=B3#1163?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/menu-item/menu-item.tsx | 13 +++++-- .../devui/menu/src/composables/use-store.ts | 35 +++++++++++++++++++ packages/devui-vue/devui/menu/src/menu.tsx | 7 ++++ 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 packages/devui-vue/devui/menu/src/composables/use-store.ts 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..bc6893b791 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'); @@ -32,12 +34,16 @@ export default defineComponent({ const rootMenuEmit = inject('rootMenuEmit') as (eventName: string, ...args: unknown[]) => void; const useRouter = inject('useRouter') as boolean; const router = instance?.appContext.config.globalProperties.$router as Router; + const preSelectedRecord = ref(isSelect.value); const classObject = computed(()=>({ [`${ns.b()}-item`]: true, [`${ns.b()}-item-isCollapsed`]: isCollapsed.value, [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 +51,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..c040eca2db --- /dev/null +++ b/packages/devui-vue/devui/menu/src/composables/use-store.ts @@ -0,0 +1,35 @@ +interface record { + [x: string]: { + [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 + 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); + } + emit(eventName: string, ...args: any[]): void{ + recordTable[this.rootMenuName][eventName].forEach((fn)=>fn(...args)); + } + off(eventName: string, fn: (...args: []) => void){ + const idx = recordTable[this.rootMenuName][eventName].indexOf(fn); + if (idx >= 0) { + recordTable[this.rootMenuName][eventName].splice(idx, 1); + } + } +} + +export function useStore(rootName: string){ + 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']); From 87f4ca3015f9b991e6109f632f0caa84d1d581b8 Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Tue, 9 Aug 2022 14:55:19 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(menu):=20=E4=BF=AE=E5=A4=8Deslint?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/menu/src/components/menu-item/menu-item.tsx | 1 - packages/devui-vue/devui/menu/src/composables/use-store.ts | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) 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 bc6893b791..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 @@ -34,7 +34,6 @@ export default defineComponent({ const rootMenuEmit = inject('rootMenuEmit') as (eventName: string, ...args: unknown[]) => void; const useRouter = inject('useRouter') as boolean; const router = instance?.appContext.config.globalProperties.$router as Router; - const preSelectedRecord = ref(isSelect.value); const classObject = computed(()=>({ [`${ns.b()}-item`]: true, [`${ns.b()}-item-isCollapsed`]: isCollapsed.value, diff --git a/packages/devui-vue/devui/menu/src/composables/use-store.ts b/packages/devui-vue/devui/menu/src/composables/use-store.ts index c040eca2db..9fcca009d1 100644 --- a/packages/devui-vue/devui/menu/src/composables/use-store.ts +++ b/packages/devui-vue/devui/menu/src/composables/use-store.ts @@ -1,5 +1,6 @@ interface record { [x: string]: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any [eventName: string]: ((...args: any[]) => void)[]; }; } @@ -10,16 +11,18 @@ export class Store{ 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){ + 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); @@ -27,7 +30,7 @@ export class Store{ } } -export function useStore(rootName: string){ +export function useStore(rootName: string): Store{ if (!recordTable[rootName]){ Reflect.set(recordTable, rootName, {}); }