<template>
|
<Menu
|
:selectedKeys="menuState.selectedKeys"
|
:defaultSelectedKeys="menuState.defaultSelectedKeys"
|
:mode="mode"
|
:openKeys="getOpenKeys"
|
:inlineIndent="inlineIndent"
|
:theme="theme"
|
@open-change="handleOpenChange"
|
:class="getMenuClass"
|
@click="handleMenuClick"
|
:subMenuOpenDelay="0.2"
|
v-bind="getInlineCollapseOptions"
|
>
|
<template v-for="item in items" :key="item.path">
|
<BasicSubMenuItem :item="item" :theme="theme" :isHorizontal="isHorizontal" />
|
</template>
|
</Menu>
|
</template>
|
<script lang="ts" setup>
|
import type { MenuState } from './types';
|
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 { useOpenKeys } from './useOpenKeys';
|
import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router';
|
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';
|
|
defineOptions({ name: 'BasicMenu' });
|
|
const props = defineProps(basicProps);
|
|
const emit = defineEmits(['menuClick']);
|
|
const isClickGo = ref(false);
|
const currentActiveMenu = ref('');
|
|
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');
|
</style>
|