vben
2021-08-24 56a966cfbf8db5b29a42185f0f25a0e800c30dbb
提交 | 用户 | age
cbcd90 1 <template>
a65ad9 2   <Menu
V 3     :selectedKeys="selectedKeys"
4     :defaultSelectedKeys="defaultSelectedKeys"
5     :mode="mode"
6     :openKeys="getOpenKeys"
7     :inlineIndent="inlineIndent"
8     :theme="theme"
9     @openChange="handleOpenChange"
10     :class="getMenuClass"
11     @click="handleMenuClick"
12     :subMenuOpenDelay="0.2"
13     v-bind="getInlineCollapseOptions"
14   >
15     <template v-for="item in items" :key="item.path">
0ec1a6 16       <BasicSubMenuItem :item="item" :theme="theme" :isHorizontal="isHorizontal" />
a65ad9 17     </template>
V 18   </Menu>
cbcd90 19 </template>
V 20 <script lang="ts">
21   import type { MenuState } from './types';
a65ad9 22   import { computed, defineComponent, unref, reactive, watch, toRefs, ref } from 'vue';
cbcd90 23   import { Menu } from 'ant-design-vue';
V 24   import BasicSubMenuItem from './components/BasicSubMenuItem.vue';
25   import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
26   import { useOpenKeys } from './useOpenKeys';
a65ad9 27   import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router';
cbcd90 28   import { isFunction } from '/@/utils/is';
V 29   import { basicProps } from './props';
30   import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
31   import { REDIRECT_NAME } from '/@/router/constant';
32   import { useDesign } from '/@/hooks/web/useDesign';
a65ad9 33   import { getCurrentParentPath } from '/@/router/menus';
6bb19f 34   import { listenerRouteChange } from '/@/logics/mitt/routeChange';
0ec1a6 35   import { getAllParentPath } from '/@/router/helper/menuHelper';
cbcd90 36
V 37   export default defineComponent({
38     name: 'BasicMenu',
39     components: {
40       Menu,
41       BasicSubMenuItem,
42     },
43     props: basicProps,
44     emits: ['menuClick'],
45     setup(props, { emit }) {
46       const isClickGo = ref(false);
6d5c49 47       const currentActiveMenu = ref('');
cbcd90 48
V 49       const menuState = reactive<MenuState>({
50         defaultSelectedKeys: [],
51         openKeys: [],
52         selectedKeys: [],
53         collapsedOpenKeys: [],
54       });
55
56       const { prefixCls } = useDesign('basic-menu');
57       const { items, mode, accordion } = toRefs(props);
58
e15b4f 59       const { getCollapsed, getTopMenuAlign, getSplit } = useMenuSetting();
cbcd90 60
V 61       const { currentRoute } = useRouter();
62
63       const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(
64         menuState,
65         items,
e15b4f 66         mode as any,
56a966 67         accordion,
cbcd90 68       );
V 69
a65ad9 70       const getIsTopMenu = computed(() => {
cbcd90 71         const { type, mode } = props;
a65ad9 72
V 73         return (
74           (type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL) ||
75           (props.isHorizontal && unref(getSplit))
76         );
77       });
78
79       const getMenuClass = computed(() => {
de2555 80         const align = props.isHorizontal && unref(getSplit) ? 'start' : unref(getTopMenuAlign);
cbcd90 81         return [
V 82           prefixCls,
de2555 83           `justify-${align}`,
cbcd90 84           {
a65ad9 85             [`${prefixCls}__second`]: !props.isHorizontal && unref(getSplit),
V 86             [`${prefixCls}__sidebar-hor`]: unref(getIsTopMenu),
cbcd90 87           },
V 88         ];
89       });
90
91       const getInlineCollapseOptions = computed(() => {
92         const isInline = props.mode === MenuModeEnum.INLINE;
93
94         const inlineCollapseOptions: { inlineCollapsed?: boolean } = {};
95         if (isInline) {
ed213d 96           inlineCollapseOptions.inlineCollapsed = props.mixSider ? false : unref(getCollapsed);
cbcd90 97         }
V 98         return inlineCollapseOptions;
99       });
100
6bb19f 101       listenerRouteChange((route) => {
a65ad9 102         if (route.name === REDIRECT_NAME) return;
V 103         handleMenuChange(route);
15567e 104         currentActiveMenu.value = route.meta?.currentActiveMenu as string;
6d5c49 105
V 106         if (unref(currentActiveMenu)) {
107           menuState.selectedKeys = [unref(currentActiveMenu)];
108           setOpenKeys(unref(currentActiveMenu));
819bcb 109         }
V 110       });
cbcd90 111
97180e 112       !props.mixSider &&
V 113         watch(
114           () => props.items,
115           () => {
116             handleMenuChange();
56a966 117           },
97180e 118         );
cbcd90 119
0ec1a6 120       async function handleMenuClick({ key }: { key: string; keyPath: string[] }) {
cbcd90 121         const { beforeClickFn } = props;
V 122         if (beforeClickFn && isFunction(beforeClickFn)) {
123           const flag = await beforeClickFn(key);
124           if (!flag) return;
125         }
126         emit('menuClick', key);
127
128         isClickGo.value = true;
0ec1a6 129         // const parentPath = await getCurrentParentPath(key);
V 130
131         // menuState.openKeys = [parentPath];
cbcd90 132         menuState.selectedKeys = [key];
V 133       }
134
a65ad9 135       async function handleMenuChange(route?: RouteLocationNormalizedLoaded) {
cbcd90 136         if (unref(isClickGo)) {
V 137           isClickGo.value = false;
138           return;
139         }
a65ad9 140         const path = (route || unref(currentRoute)).path;
819bcb 141         setOpenKeys(path);
6d5c49 142         if (unref(currentActiveMenu)) return;
c774a6 143         if (props.isHorizontal && unref(getSplit)) {
a65ad9 144           const parentPath = await getCurrentParentPath(path);
V 145           menuState.selectedKeys = [parentPath];
146         } else {
0ec1a6 147           const parentPaths = await getAllParentPath(props.items, path);
V 148           menuState.selectedKeys = parentPaths;
a65ad9 149         }
cbcd90 150       }
V 151
152       return {
153         handleMenuClick,
154         getInlineCollapseOptions,
155         getMenuClass,
156         handleOpenChange,
157         getOpenKeys,
158         ...toRefs(menuState),
159       };
160     },
161   });
162 </script>
163 <style lang="less">
164   @import './index.less';
165 </style>