| | |
| | | <template> |
| | | <Menu |
| | | :selectedKeys="selectedKeys" |
| | | :defaultSelectedKeys="defaultSelectedKeys" |
| | | :selectedKeys="menuState.selectedKeys" |
| | | :defaultSelectedKeys="menuState.defaultSelectedKeys" |
| | | :mode="mode" |
| | | :openKeys="getOpenKeys" |
| | | :inlineIndent="inlineIndent" |
| | |
| | | </template> |
| | | </Menu> |
| | | </template> |
| | | <script lang="ts"> |
| | | <script lang="ts" setup> |
| | | import type { MenuState } from './types'; |
| | | import { computed, defineComponent, unref, reactive, watch, toRefs, ref } from 'vue'; |
| | | import { Menu } from 'ant-design-vue'; |
| | | import { computed, unref, reactive, watch, toRefs, ref } from 'vue'; |
| | | import { Menu, MenuProps } from 'ant-design-vue'; |
| | | import BasicSubMenuItem from './components/BasicSubMenuItem.vue'; |
| | | import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; |
| | | import { MenuModeEnum, MenuTypeEnum } from '@/enums/menuEnum'; |
| | | import { useOpenKeys } from './useOpenKeys'; |
| | | import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router'; |
| | | import { isFunction } from '/@/utils/is'; |
| | | import { isFunction } from '@/utils/is'; |
| | | import { basicProps } from './props'; |
| | | import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; |
| | | import { REDIRECT_NAME } from '/@/router/constant'; |
| | | import { useDesign } from '/@/hooks/web/useDesign'; |
| | | import { getCurrentParentPath } from '/@/router/menus'; |
| | | import { listenerRouteChange } from '/@/logics/mitt/routeChange'; |
| | | import { getAllParentPath } from '/@/router/helper/menuHelper'; |
| | | import { useMenuSetting } from '@/hooks/setting/useMenuSetting'; |
| | | import { REDIRECT_NAME } from '@/router/constant'; |
| | | import { useDesign } from '@/hooks/web/useDesign'; |
| | | import { getCurrentParentPath } from '@/router/menus'; |
| | | import { listenerRouteChange } from '@/logics/mitt/routeChange'; |
| | | import { getAllParentPath } from '@/router/helper/menuHelper'; |
| | | |
| | | export default defineComponent({ |
| | | name: 'BasicMenu', |
| | | components: { |
| | | Menu, |
| | | BasicSubMenuItem, |
| | | }, |
| | | props: basicProps, |
| | | emits: ['menuClick'], |
| | | setup(props, { emit }) { |
| | | const isClickGo = ref(false); |
| | | const currentActiveMenu = ref(''); |
| | | defineOptions({ name: 'BasicMenu' }); |
| | | |
| | | const menuState = reactive<MenuState>({ |
| | | defaultSelectedKeys: [], |
| | | openKeys: [], |
| | | selectedKeys: [], |
| | | collapsedOpenKeys: [], |
| | | }); |
| | | const props = defineProps(basicProps); |
| | | |
| | | const { prefixCls } = useDesign('basic-menu'); |
| | | const { items, mode, accordion } = toRefs(props); |
| | | const emit = defineEmits(['menuClick']); |
| | | |
| | | const { getCollapsed, getTopMenuAlign, getSplit } = useMenuSetting(); |
| | | const isClickGo = ref(false); |
| | | const currentActiveMenu = ref(''); |
| | | |
| | | const { currentRoute } = useRouter(); |
| | | |
| | | const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys( |
| | | menuState, |
| | | items, |
| | | mode as any, |
| | | accordion, |
| | | ); |
| | | |
| | | const getIsTopMenu = computed(() => { |
| | | const { type, mode } = props; |
| | | |
| | | return ( |
| | | (type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL) || |
| | | (props.isHorizontal && unref(getSplit)) |
| | | ); |
| | | }); |
| | | |
| | | const getMenuClass = computed(() => { |
| | | const align = props.isHorizontal && unref(getSplit) ? 'start' : unref(getTopMenuAlign); |
| | | return [ |
| | | prefixCls, |
| | | `justify-${align}`, |
| | | { |
| | | [`${prefixCls}__second`]: !props.isHorizontal && unref(getSplit), |
| | | [`${prefixCls}__sidebar-hor`]: unref(getIsTopMenu), |
| | | }, |
| | | ]; |
| | | }); |
| | | |
| | | const getInlineCollapseOptions = computed(() => { |
| | | const isInline = props.mode === MenuModeEnum.INLINE; |
| | | |
| | | const inlineCollapseOptions: { inlineCollapsed?: boolean } = {}; |
| | | if (isInline) { |
| | | inlineCollapseOptions.inlineCollapsed = props.mixSider ? false : unref(getCollapsed); |
| | | } |
| | | return inlineCollapseOptions; |
| | | }); |
| | | |
| | | listenerRouteChange((route) => { |
| | | if (route.name === REDIRECT_NAME) return; |
| | | handleMenuChange(route); |
| | | currentActiveMenu.value = route.meta?.currentActiveMenu as string; |
| | | |
| | | if (unref(currentActiveMenu)) { |
| | | menuState.selectedKeys = [unref(currentActiveMenu)]; |
| | | setOpenKeys(unref(currentActiveMenu)); |
| | | } |
| | | }); |
| | | |
| | | !props.mixSider && |
| | | watch( |
| | | () => props.items, |
| | | () => { |
| | | handleMenuChange(); |
| | | }, |
| | | ); |
| | | |
| | | async function handleMenuClick({ key }: { key: string; keyPath: string[] }) { |
| | | const { beforeClickFn } = props; |
| | | if (beforeClickFn && isFunction(beforeClickFn)) { |
| | | const flag = await beforeClickFn(key); |
| | | if (!flag) return; |
| | | } |
| | | emit('menuClick', key); |
| | | |
| | | isClickGo.value = true; |
| | | menuState.selectedKeys = [key]; |
| | | } |
| | | |
| | | async function handleMenuChange(route?: RouteLocationNormalizedLoaded) { |
| | | if (unref(isClickGo)) { |
| | | isClickGo.value = false; |
| | | return; |
| | | } |
| | | const path = |
| | | (route || unref(currentRoute)).meta?.currentActiveMenu || |
| | | (route || unref(currentRoute)).path; |
| | | setOpenKeys(path); |
| | | if (unref(currentActiveMenu)) return; |
| | | if (props.isHorizontal && unref(getSplit)) { |
| | | const parentPath = await getCurrentParentPath(path); |
| | | menuState.selectedKeys = [parentPath]; |
| | | } else { |
| | | const parentPaths = await getAllParentPath(props.items, path); |
| | | menuState.selectedKeys = parentPaths; |
| | | } |
| | | } |
| | | |
| | | return { |
| | | handleMenuClick, |
| | | getInlineCollapseOptions, |
| | | getMenuClass, |
| | | handleOpenChange, |
| | | getOpenKeys, |
| | | ...toRefs(menuState), |
| | | }; |
| | | }, |
| | | const menuState = reactive<MenuState>({ |
| | | defaultSelectedKeys: [], |
| | | openKeys: [], |
| | | selectedKeys: [], |
| | | collapsedOpenKeys: [], |
| | | }); |
| | | |
| | | const { prefixCls } = useDesign('basic-menu'); |
| | | const { items, mode, accordion } = toRefs(props); |
| | | |
| | | const { getCollapsed, getTopMenuAlign, getSplit } = useMenuSetting(); |
| | | |
| | | const { currentRoute } = useRouter(); |
| | | |
| | | const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys( |
| | | menuState, |
| | | items, |
| | | mode as any, |
| | | accordion, |
| | | ); |
| | | |
| | | const getIsTopMenu = computed(() => { |
| | | const { type, mode } = props; |
| | | |
| | | return ( |
| | | (type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL) || |
| | | (props.isHorizontal && unref(getSplit)) |
| | | ); |
| | | }); |
| | | |
| | | const getMenuClass = computed(() => { |
| | | const align = props.isHorizontal && unref(getSplit) ? 'start' : unref(getTopMenuAlign); |
| | | return [ |
| | | prefixCls, |
| | | `justify-${align}`, |
| | | { |
| | | [`${prefixCls}__second`]: !props.isHorizontal && unref(getSplit), |
| | | [`${prefixCls}__sidebar-hor`]: unref(getIsTopMenu), |
| | | }, |
| | | ]; |
| | | }); |
| | | |
| | | const getInlineCollapseOptions = computed(() => { |
| | | const isInline = props.mode === MenuModeEnum.INLINE; |
| | | |
| | | const inlineCollapseOptions: { inlineCollapsed?: boolean } = {}; |
| | | if (isInline) { |
| | | inlineCollapseOptions.inlineCollapsed = props.mixSider ? false : unref(getCollapsed); |
| | | } |
| | | return inlineCollapseOptions; |
| | | }); |
| | | |
| | | listenerRouteChange((route) => { |
| | | if (route.name === REDIRECT_NAME) return; |
| | | handleMenuChange(route); |
| | | currentActiveMenu.value = route.meta?.currentActiveMenu as string; |
| | | |
| | | if (unref(currentActiveMenu)) { |
| | | menuState.selectedKeys = [unref(currentActiveMenu)]; |
| | | setOpenKeys(unref(currentActiveMenu)); |
| | | } |
| | | }); |
| | | |
| | | !props.mixSider && |
| | | watch( |
| | | () => props.items, |
| | | () => { |
| | | handleMenuChange(); |
| | | }, |
| | | ); |
| | | |
| | | const handleMenuClick: MenuProps['onClick'] = async ({ key }) => { |
| | | const { beforeClickFn } = props; |
| | | if (beforeClickFn && isFunction(beforeClickFn)) { |
| | | const flag = await beforeClickFn(key); |
| | | if (!flag) return; |
| | | } |
| | | emit('menuClick', key); |
| | | |
| | | isClickGo.value = true; |
| | | menuState.selectedKeys = [key]; |
| | | }; |
| | | |
| | | async function handleMenuChange(route?: RouteLocationNormalizedLoaded) { |
| | | if (unref(isClickGo)) { |
| | | isClickGo.value = false; |
| | | return; |
| | | } |
| | | const path = |
| | | (route || unref(currentRoute)).meta?.currentActiveMenu || (route || unref(currentRoute)).path; |
| | | setOpenKeys(path); |
| | | if (unref(currentActiveMenu)) return; |
| | | if (props.isHorizontal && unref(getSplit)) { |
| | | const parentPath = await getCurrentParentPath(path); |
| | | menuState.selectedKeys = [parentPath]; |
| | | } else { |
| | | const parentPaths = await getAllParentPath(props.items, path); |
| | | menuState.selectedKeys = parentPaths; |
| | | } |
| | | } |
| | | </script> |
| | | <style lang="less"> |
| | | @import url('./index.less'); |