fix(menu): ensure the menu is activated correctly,fix #432
| | |
| | | "@iconify/iconify": "^2.0.0-rc.6", |
| | | "@vueuse/core": "^4.6.2", |
| | | "@zxcvbn-ts/core": "^0.3.0", |
| | | "ant-design-vue": "2.1.0", |
| | | "ant-design-vue": "2.1.1", |
| | | "apexcharts": "^3.26.0", |
| | | "axios": "^0.21.1", |
| | | "crypto-js": "^4.0.0", |
| | |
| | | </Menu> |
| | | </template> |
| | | <script lang="ts"> |
| | | import type { PropType } from 'vue'; |
| | | import type { MenuState } from './types'; |
| | | import type { Menu as MenuType } from '/@/router/types'; |
| | | |
| | |
| | | const { currentRoute } = useRouter(); |
| | | const { prefixCls } = useDesign('simple-menu'); |
| | | const { items, accordion, mixSider, collapse } = toRefs(props); |
| | | |
| | | const { setOpenKeys, getOpenKeys } = useOpenKeys( |
| | | menuState, |
| | | items, |
| | |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | watch( |
| | | () => props.items, |
| | | () => { |
| | | setOpenKeys(currentRoute.value.path); |
| | | }, |
| | | { flush: 'post' } |
| | | ); |
| | | |
| | | listenerRouteChange((route) => { |
| | |
| | | menuState.activeName = path; |
| | | |
| | | setOpenKeys(path); |
| | | // if (unref(currentActiveMenu)) return; |
| | | } |
| | | |
| | | async function handleSelect(key: string) { |
| | |
| | | </template> |
| | | <script lang="ts"> |
| | | import type { Menu } from '/@/router/types'; |
| | | import type { PropType } from 'vue'; |
| | | |
| | | import { defineComponent, computed } from 'vue'; |
| | | |
| | |
| | | getCurrentInstance, |
| | | provide, |
| | | } from 'vue'; |
| | | |
| | | import { useDesign } from '/@/hooks/web/useDesign'; |
| | | import { propTypes } from '/@/utils/propTypes'; |
| | | import { createSimpleRootMenuContext } from './useSimpleMenuContext'; |
| | |
| | | setup() { |
| | | return { |
| | | on: { |
| | | beforeEnter(el: any) { |
| | | beforeEnter(el) { |
| | | addClass(el, 'collapse-transition'); |
| | | if (!el.dataset) el.dataset = {}; |
| | | |
| | |
| | | el.style.paddingBottom = 0; |
| | | }, |
| | | |
| | | enter(el: any) { |
| | | enter(el) { |
| | | el.dataset.oldOverflow = el.style.overflow; |
| | | if (el.scrollHeight !== 0) { |
| | | el.style.height = el.scrollHeight + 'px'; |
| | |
| | | el.style.overflow = 'hidden'; |
| | | }, |
| | | |
| | | afterEnter(el: any) { |
| | | afterEnter(el) { |
| | | removeClass(el, 'collapse-transition'); |
| | | el.style.height = ''; |
| | | el.style.overflow = el.dataset.oldOverflow; |
| | | }, |
| | | |
| | | beforeLeave(el: any) { |
| | | beforeLeave(el) { |
| | | if (!el.dataset) el.dataset = {}; |
| | | el.dataset.oldPaddingTop = el.style.paddingTop; |
| | | el.dataset.oldPaddingBottom = el.style.paddingBottom; |
| | |
| | | el.style.overflow = 'hidden'; |
| | | }, |
| | | |
| | | leave(el: any) { |
| | | leave(el) { |
| | | if (el.scrollHeight !== 0) { |
| | | addClass(el, 'collapse-transition'); |
| | | el.style.height = 0; |
| | |
| | | } |
| | | }, |
| | | |
| | | afterLeave(el: any) { |
| | | afterLeave(el) { |
| | | removeClass(el, 'collapse-transition'); |
| | | el.style.height = ''; |
| | | el.style.overflow = el.dataset.oldOverflow; |
| | |
| | | import { isBoolean, isObject } from '/@/utils/is'; |
| | | import Mitt from '/@/utils/mitt'; |
| | | |
| | | const DELAY = 200; |
| | | const DELAY = 250; |
| | | export default defineComponent({ |
| | | name: 'SubMenu', |
| | | components: { |
| | |
| | | uidList: [], |
| | | list: [], |
| | | }; |
| | | const ret = []; |
| | | const ret: any[] = []; |
| | | while (parent && parent.type.name !== 'Menu') { |
| | | if (parent.type.name === 'SubMenu') { |
| | | ret.push(parent); |
| | |
| | | import { getAllParentPath } from '/@/router/helper/menuHelper'; |
| | | |
| | | import { useTimeoutFn } from '/@/hooks/core/useTimeout'; |
| | | import { useDebounce } from '../../../hooks/core/useDebounce'; |
| | | |
| | | export function useOpenKeys( |
| | | menuState: MenuState, |
| | |
| | | accordion: Ref<boolean>, |
| | | mixSider: Ref<boolean>, |
| | | collapse: Ref<boolean> |
| | | // mode: Ref<MenuModeEnum>, |
| | | ) { |
| | | const [debounceSetOpenKeys] = useDebounce(setOpenKeys, 50); |
| | | async function setOpenKeys(path: string) { |
| | | // if (mode.value === MenuModeEnum.HORIZONTAL) { |
| | | // return; |
| | | // } |
| | | const native = !mixSider.value; |
| | | const menuList = toRaw(menus.value); |
| | | useTimeoutFn( |
| | | () => { |
| | | const menuList = toRaw(menus.value); |
| | | if (menuList?.length === 0) { |
| | | menuState.activeSubMenuNames = []; |
| | | menuState.openNames = []; |
| | | return; |
| | | } |
| | | const keys = getAllParentPath(menuList, path); |
| | | |
| | | if (!unref(accordion)) { |
| | | menuState.openNames = uniq([...menuState.openNames, ...keys]); |
| | | } else { |
| | |
| | | } |
| | | menuState.activeSubMenuNames = menuState.openNames; |
| | | }, |
| | | 16, |
| | | 30, |
| | | native |
| | | ); |
| | | } |
| | |
| | | return unref(collapse) ? [] : menuState.openNames; |
| | | }); |
| | | |
| | | return { setOpenKeys, getOpenKeys }; |
| | | return { setOpenKeys: debounceSetOpenKeys, getOpenKeys }; |
| | | } |
| | |
| | | }, |
| | | ]; |
| | | }); |
| | | |
| | | 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 |
| | | * @param menu |
| | |
| | | } |
| | | |
| | | function renderMenu() { |
| | | const menus = unref(menusRef); |
| | | const { menus, ...menuProps } = unref(getCommonProps); |
| | | // console.log(menus); |
| | | if (!menus || !menus.length) return null; |
| | | return !props.isHorizontal ? ( |
| | | <SimpleMenu |
| | | beforeClickFn={beforeMenuClickFn} |
| | | items={menus} |
| | | theme={unref(getComputedMenuTheme)} |
| | | accordion={unref(getAccordion)} |
| | | collapse={unref(getCollapsed)} |
| | | collapsedShowTitle={unref(getCollapsedShowTitle)} |
| | | onMenuClick={handleMenuClick} |
| | | /> |
| | | <SimpleMenu {...menuProps} items={menus} /> |
| | | ) : ( |
| | | <BasicMenu |
| | | beforeClickFn={beforeMenuClickFn} |
| | | {...menuProps} |
| | | isHorizontal={props.isHorizontal} |
| | | type={unref(getMenuType)} |
| | | collapsedShowTitle={unref(getCollapsedShowTitle)} |
| | | showLogo={unref(getIsShowLogo)} |
| | | mode={unref(getComputedMenuMode)} |
| | | theme={unref(getComputedMenuTheme)} |
| | | items={menus} |
| | | accordion={unref(getAccordion)} |
| | | onMenuClick={handleMenuClick} |
| | | /> |
| | | ); |
| | | } |
| | |
| | | ); |
| | | |
| | | // split Menu changes |
| | | watch([() => getSplit.value], () => { |
| | | if (unref(splitNotLeft)) return; |
| | | genMenus(); |
| | | }); |
| | | watch( |
| | | () => getSplit.value, |
| | | () => { |
| | | if (unref(splitNotLeft)) return; |
| | | genMenus(); |
| | | } |
| | | ); |
| | | |
| | | // Handle left menu split |
| | | async function handleSplitLeftMenu(parentPath: string) { |
| | |
| | | VNode, |
| | | ComponentPublicInstance, |
| | | FunctionalComponent, |
| | | PropType as VuePropType, |
| | | } from 'vue'; |
| | | |
| | | declare global { |
| | | // declare interface Window { |
| | | // Global vue app instance |
| | | // __APP__: App<Element>; |
| | | // } |
| | | |
| | | // vue |
| | | declare type PropType<T> = VuePropType<T>; |
| | | |
| | | export type Writable<T> = { |
| | | -readonly [P in keyof T]: T[P]; |
| | | }; |
| | |
| | | dependencies: |
| | | color-convert "^2.0.1" |
| | | |
| | | ant-design-vue@2.1.0: |
| | | version "2.1.0" |
| | | resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.0.tgz#2489240f638f39874281e237544b857ebce52d18" |
| | | integrity sha512-wzgwHRuwZrSvixccNlvas2gTWBkmfMrifbSsP+ga8VV6F0C6DdlimeFo+P99AxnVgpNVk8OUq9RVDQjb1UGk6g== |
| | | ant-design-vue@2.1.1: |
| | | version "2.1.1" |
| | | resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.1.tgz#5c2f3d86177e197f6dbb167f691a9d10104e61c3" |
| | | integrity sha512-ohTEIBFRkODRTFXRHeizL/uKNOZY5+4r2y/GXiKEdvrxiTRgHgDNMWKsncG/+G6MXxOIe2Reg+r8jHS8nGDqtQ== |
| | | dependencies: |
| | | "@ant-design-vue/use" "^0.0.1-0" |
| | | "@ant-design/icons-vue" "^6.0.0" |