Commit cbcd9098671e2fff9152976b7e9e815fea29d074

Authored by vben
1 parent f81c4019

wip(menu): perf menu

src/components/Application/src/AppLogo.vue
... ... @@ -66,8 +66,9 @@
66 66 .@{prefix-cls} {
67 67 display: flex;
68 68 align-items: center;
69   - padding-left: 12px;
  69 + padding-left: 7px;
70 70 cursor: pointer;
  71 + transition: all 0.2s ease;
71 72  
72 73 &.collapsed-show-title {
73 74 padding-left: 20px;
... ...
src/components/Menu/index.ts
... ... @@ -2,6 +2,8 @@ import { withInstall } from '../util';
2 2  
3 3 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
4 4  
5   -export const BasicMenu = createAsyncComponent(() => import('./src/BasicMenu'), { loading: false });
  5 +export const BasicMenu = createAsyncComponent(() => import('./src/BasicMenu.vue'), {
  6 + loading: false,
  7 +});
6 8  
7 9 withInstall(BasicMenu);
... ...
src/components/Menu/src/BasicMenu.tsx renamed to src/components/Menu/src/BasicMenu.vue
1   -import './index.less';
2   -
3   -import type { MenuState } from './types';
4   -import type { Menu as MenuType } from '/@/router/types';
5   -
6   -import {
7   - computed,
8   - defineComponent,
9   - unref,
10   - reactive,
11   - watch,
12   - toRefs,
13   - ComputedRef,
14   - ref,
15   - CSSProperties,
16   -} from 'vue';
17   -import { Menu } from 'ant-design-vue';
18   -import MenuContent from './MenuContent';
19   -// import { ScrollContainer } from '/@/components/Container';
20   -// import { BasicArrow } from '/@/components/Basic';
21   -
22   -import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
23   -import { ThemeEnum } from '/@/enums/appEnum';
24   -
25   -import { appStore } from '/@/store/modules/app';
26   -
27   -import { useOpenKeys } from './useOpenKeys';
28   -import { useRouter } from 'vue-router';
29   -
30   -import { isFunction } from '/@/utils/is';
31   -import { getSlot } from '/@/utils/helper/tsxHelper';
32   -import { menuHasChildren } from './helper';
33   -import { getCurrentParentPath } from '/@/router/menus';
34   -
35   -import { basicProps } from './props';
36   -import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
37   -import { REDIRECT_NAME } from '/@/router/constant';
38   -import { tabStore } from '/@/store/modules/tab';
39   -import { useDesign } from '/@/hooks/web/useDesign';
40   -export default defineComponent({
41   - name: 'BasicMenu',
42   - props: basicProps,
43   - emits: ['menuClick'],
44   - setup(props, { slots, emit }) {
45   - const currentParentPath = ref('');
46   - const isClickGo = ref(false);
47   -
48   - const menuState = reactive<MenuState>({
49   - defaultSelectedKeys: [],
50   - mode: props.mode,
51   - theme: computed(() => props.theme) as ComputedRef<ThemeEnum>,
52   - openKeys: [],
53   - selectedKeys: [],
54   - collapsedOpenKeys: [],
55   - });
56   -
57   - const { prefixCls } = useDesign('basic-menu');
58   -
59   - const { items, mode, accordion } = toRefs(props);
60   -
61   - const { getCollapsed, getIsHorizontal, getTopMenuAlign, getSplit } = useMenuSetting();
  1 +<template>
  2 + <slot name="header" v-if="!getIsHorizontal" />
  3 + <ScrollContainer :class="`${prefixCls}-wrapper`" :style="getWrapperStyle">
  4 + <Menu
  5 + :selectedKeys="selectedKeys"
  6 + :defaultSelectedKeys="defaultSelectedKeys"
  7 + :mode="mode"
  8 + :openKeys="getOpenKeys"
  9 + :inlineIndent="inlineIndent"
  10 + :theme="theme"
  11 + @openChange="handleOpenChange"
  12 + :class="getMenuClass"
  13 + @click="handleMenuClick"
  14 + :subMenuOpenDelay="0.2"
  15 + v-bind="getInlineCollapseOptions"
  16 + >
  17 + <template v-for="item in items" :key="item.path">
  18 + <BasicSubMenuItem
  19 + :item="item"
  20 + :theme="theme"
  21 + :level="1"
  22 + :appendClass="appendClass"
  23 + :parentPath="currentParentPath"
  24 + :showTitle="showTitle"
  25 + :isHorizontal="isHorizontal"
  26 + />
  27 + </template>
  28 + </Menu>
  29 + </ScrollContainer>
  30 +</template>
  31 +<script lang="ts">
  32 + import type { MenuState } from './types';
  33 +
  34 + import {
  35 + computed,
  36 + defineComponent,
  37 + unref,
  38 + reactive,
  39 + watch,
  40 + toRefs,
  41 + ref,
  42 + CSSProperties,
  43 + } from 'vue';
  44 + import { Menu } from 'ant-design-vue';
  45 + import BasicSubMenuItem from './components/BasicSubMenuItem.vue';
  46 + import { ScrollContainer } from '/@/components/Container';
  47 +
  48 + import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
  49 +
  50 + import { appStore } from '/@/store/modules/app';
  51 +
  52 + import { useOpenKeys } from './useOpenKeys';
  53 + import { useRouter } from 'vue-router';
  54 +
  55 + import { isFunction } from '/@/utils/is';
  56 + import { getCurrentParentPath } from '/@/router/menus';
  57 +
  58 + import { basicProps } from './props';
  59 + import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
  60 + import { REDIRECT_NAME } from '/@/router/constant';
  61 + import { tabStore } from '/@/store/modules/tab';
  62 + import { useDesign } from '/@/hooks/web/useDesign';
  63 + // import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
  64 +
  65 + export default defineComponent({
  66 + name: 'BasicMenu',
  67 + components: {
  68 + Menu,
  69 + ScrollContainer,
  70 + BasicSubMenuItem,
  71 + // BasicSubMenuItem: createAsyncComponent(() => import('./components/BasicSubMenuItem.vue')),
  72 + },
  73 + props: basicProps,
  74 + emits: ['menuClick'],
  75 + setup(props, { emit }) {
  76 + const currentParentPath = ref('');
  77 + const isClickGo = ref(false);
  78 +
  79 + const menuState = reactive<MenuState>({
  80 + defaultSelectedKeys: [],
  81 + openKeys: [],
  82 + selectedKeys: [],
  83 + collapsedOpenKeys: [],
  84 + });
  85 +
  86 + const { prefixCls } = useDesign('basic-menu');
  87 + const { items, mode, accordion } = toRefs(props);
  88 +
  89 + const { getCollapsed, getIsHorizontal, getTopMenuAlign, getSplit } = useMenuSetting();
  90 +
  91 + const { currentRoute } = useRouter();
  92 +
  93 + const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(
  94 + menuState,
  95 + items,
  96 + mode,
  97 + accordion
  98 + );
62 99  
63   - const { currentRoute } = useRouter();
  100 + const getMenuClass = computed(() => {
  101 + const { type, mode } = props;
  102 + return [
  103 + prefixCls,
  104 + `justify-${unref(getTopMenuAlign)}`,
  105 + {
  106 + [`${prefixCls}--hide-title`]: !unref(showTitle),
  107 + [`${prefixCls}--collapsed-show-title`]: props.collapsedShowTitle,
  108 + [`${prefixCls}__second`]:
  109 + !props.isHorizontal && appStore.getProjectConfig.menuSetting.split,
  110 + [`${prefixCls}__sidebar-hor`]:
  111 + type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL,
  112 + },
  113 + ];
  114 + });
  115 +
  116 + const showTitle = computed(() => props.collapsedShowTitle && unref(getCollapsed));
  117 +
  118 + const getInlineCollapseOptions = computed(() => {
  119 + const isInline = props.mode === MenuModeEnum.INLINE;
  120 +
  121 + const inlineCollapseOptions: { inlineCollapsed?: boolean } = {};
  122 + if (isInline) {
  123 + inlineCollapseOptions.inlineCollapsed = unref(getCollapsed);
  124 + }
  125 + return inlineCollapseOptions;
  126 + });
  127 +
  128 + const getWrapperStyle = computed(
  129 + (): CSSProperties => {
  130 + return {
  131 + height: `calc(100% - ${props.showLogo ? '48px' : '0px'})`,
  132 + overflowY: 'hidden',
  133 + };
  134 + }
  135 + );
64 136  
65   - const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(
66   - menuState,
67   - items,
68   - mode,
69   - accordion
70   - );
  137 + watch(
  138 + () => tabStore.getCurrentTab,
  139 + () => {
  140 + if (unref(currentRoute).name === REDIRECT_NAME) return;
  141 + handleMenuChange();
  142 + unref(getSplit) && getParentPath();
  143 + }
  144 + );
71 145  
72   - const getMenuClass = computed(() => {
73   - const { type } = props;
74   - const { mode } = menuState;
75   - return [
76   - prefixCls,
77   - `justify-${unref(getTopMenuAlign)}`,
78   - {
79   - [`${prefixCls}--hide-title`]: !unref(showTitle),
80   - [`${prefixCls}--collapsed-show-title`]: props.collapsedShowTitle,
81   - [`${prefixCls}__second`]:
82   - !props.isHorizontal && appStore.getProjectConfig.menuSetting.split,
83   - [`${prefixCls}__sidebar-hor`]:
84   - type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL,
  146 + watch(
  147 + () => props.items,
  148 + () => {
  149 + handleMenuChange();
85 150 },
86   - ];
87   - });
88   -
89   - const showTitle = computed(() => props.collapsedShowTitle && unref(getCollapsed));
90   -
91   - const getInlineCollapseOptions = computed(() => {
92   - const isInline = props.mode === MenuModeEnum.INLINE;
93   -
94   - const inlineCollapseOptions: { inlineCollapsed?: boolean } = {};
95   - if (isInline) {
96   - inlineCollapseOptions.inlineCollapsed = unref(getCollapsed);
97   - }
98   - return inlineCollapseOptions;
99   - });
100   -
101   - const getWrapperStyle = computed(
102   - (): CSSProperties => {
103   - const isHorizontal = unref(getIsHorizontal) || getSplit.value;
  151 + {
  152 + immediate: true,
  153 + }
  154 + );
104 155  
105   - return {
106   - height: isHorizontal ? '100%' : `calc(100% - ${props.showLogo ? '48px' : '0px'})`,
107   - overflowY: isHorizontal ? 'hidden' : 'auto',
108   - };
109   - }
110   - );
  156 + getParentPath();
111 157  
112   - watch(
113   - () => tabStore.getCurrentTab,
114   - () => {
115   - if (unref(currentRoute).name === REDIRECT_NAME) return;
116   - handleMenuChange();
117   - unref(getSplit) && getParentPath();
118   - }
119   - );
  158 + async function getParentPath() {
  159 + const { appendClass } = props;
  160 + if (!appendClass) return '';
  161 + const parentPath = await getCurrentParentPath(unref(currentRoute).path);
120 162  
121   - watch(
122   - () => props.items,
123   - () => {
124   - handleMenuChange();
125   - },
126   - {
127   - immediate: true,
  163 + currentParentPath.value = parentPath;
128 164 }
129   - );
130   -
131   - getParentPath();
132   -
133   - async function getParentPath() {
134   - const { appendClass } = props;
135   - if (!appendClass) return '';
136   - const parentPath = await getCurrentParentPath(unref(currentRoute).path);
137   -
138   - currentParentPath.value = parentPath;
139   - }
140 165  
141   - async function handleMenuClick({ key, keyPath }: { key: string; keyPath: string[] }) {
142   - const { beforeClickFn } = props;
143   - if (beforeClickFn && isFunction(beforeClickFn)) {
144   - const flag = await beforeClickFn(key);
145   - if (!flag) return;
  166 + async function handleMenuClick({ key, keyPath }: { key: string; keyPath: string[] }) {
  167 + const { beforeClickFn } = props;
  168 + if (beforeClickFn && isFunction(beforeClickFn)) {
  169 + const flag = await beforeClickFn(key);
  170 + if (!flag) return;
  171 + }
  172 + emit('menuClick', key);
  173 +
  174 + isClickGo.value = true;
  175 + menuState.openKeys = keyPath;
  176 + menuState.selectedKeys = [key];
146 177 }
147   - emit('menuClick', key);
148 178  
149   - isClickGo.value = true;
150   - menuState.openKeys = keyPath;
151   - menuState.selectedKeys = [key];
152   - }
153   -
154   - function handleMenuChange() {
155   - if (unref(isClickGo)) {
156   - isClickGo.value = false;
157   - return;
158   - }
159   - const path = unref(currentRoute).path;
160   - if (menuState.mode !== MenuModeEnum.HORIZONTAL) {
161   - setOpenKeys(path);
  179 + function handleMenuChange() {
  180 + if (unref(isClickGo)) {
  181 + isClickGo.value = false;
  182 + return;
  183 + }
  184 + const path = unref(currentRoute).path;
  185 + if (props.mode !== MenuModeEnum.HORIZONTAL) {
  186 + setOpenKeys(path);
  187 + }
  188 + menuState.selectedKeys = [path];
162 189 }
163   - menuState.selectedKeys = [path];
164   - }
165   -
166   - // function renderExpandIcon({ key }: { key: string }) {
167   - // const isOpen = getOpenKeys.value.includes(key);
168   - // const collapsed = unref(getCollapsed);
169   - // return (
170   - // <BasicArrow
171   - // expand={isOpen}
172   - // bottom
173   - // inset
174   - // class={[
175   - // `${prefixCls}__expand-icon`,
176   - // {
177   - // [`${prefixCls}__expand-icon--collapsed`]: collapsed,
178   - // },
179   - // ]}
180   - // />
181   - // );
182   - // }
183   -
184   - function renderItem(menu: MenuType, level = 1) {
185   - return !menuHasChildren(menu) ? renderMenuItem(menu, level) : renderSubMenu(menu, level);
186   - }
187   -
188   - function renderMenuItem(menu: MenuType, level: number) {
189   - const { appendClass } = props;
190   - const isAppendActiveCls =
191   - appendClass && level === 1 && menu.path === unref(currentParentPath);
192 190  
193   - const levelCls = [
194   - `${prefixCls}-item__level${level}`,
195   - ` ${menuState.theme} `,
196   - {
197   - 'top-active-menu': isAppendActiveCls,
198   - },
199   - ];
200   - return (
201   - <Menu.Item key={menu.path} class={levelCls}>
202   - {() => [
203   - <MenuContent
204   - item={menu}
205   - showTitle={unref(showTitle)}
206   - isHorizontal={props.isHorizontal}
207   - />,
208   - ]}
209   - </Menu.Item>
210   - );
211   - }
212   -
213   - function renderSubMenu(menu: MenuType, level: number) {
214   - const levelCls = `${prefixCls}-item__level${level} ${menuState.theme} `;
215   - return (
216   - <Menu.SubMenu key={menu.path} class={levelCls}>
217   - {{
218   - title: () => [
219   - <MenuContent
220   - showTitle={unref(showTitle)}
221   - item={menu}
222   - isHorizontal={props.isHorizontal}
223   - />,
224   - ],
225   - // expandIcon: renderExpandIcon,
226   - default: () => (menu.children || []).map((item) => renderItem(item, level + 1)),
227   - }}
228   - </Menu.SubMenu>
229   - );
230   - }
231   -
232   - function renderMenu() {
233   - const { selectedKeys, defaultSelectedKeys, mode, theme } = menuState;
234   -
235   - return (
236   - <Menu
237   - selectedKeys={selectedKeys}
238   - defaultSelectedKeys={defaultSelectedKeys}
239   - mode={mode}
240   - openKeys={unref(getOpenKeys)}
241   - inlineIndent={props.inlineIndent}
242   - theme={unref(theme)}
243   - onOpenChange={handleOpenChange}
244   - class={unref(getMenuClass)}
245   - onClick={handleMenuClick}
246   - subMenuOpenDelay={0.2}
247   - {...unref(getInlineCollapseOptions)}
248   - >
249   - {{
250   - default: () => unref(items).map((item) => renderItem(item)),
251   - }}
252   - </Menu>
253   - );
254   - }
255   -
256   - return () => {
257   - return (
258   - <>
259   - {!unref(getIsHorizontal) && getSlot(slots, 'header')}
260   - <div class={`${prefixCls}-wrapper`} style={unref(getWrapperStyle)}>
261   - {renderMenu()}
262   - </div>
263   - </>
264   - );
265   - };
266   - },
267   -});
  191 + return {
  192 + prefixCls,
  193 + getIsHorizontal,
  194 + getWrapperStyle,
  195 + handleMenuClick,
  196 + getInlineCollapseOptions,
  197 + getMenuClass,
  198 + handleOpenChange,
  199 + getOpenKeys,
  200 + currentParentPath,
  201 + showTitle,
  202 + ...toRefs(menuState),
  203 + };
  204 + },
  205 + });
  206 +</script>
  207 +<style lang="less">
  208 + @import './index.less';
  209 +</style>
... ...
src/components/Menu/src/components/BasicMenuItem.vue 0 → 100644
  1 +<template>
  2 + <MenuItem :class="getLevelClass">
  3 + <MenuContent v-bind="$props" :item="item" />
  4 + </MenuItem>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent, computed } from 'vue';
  8 + import { Menu } from 'ant-design-vue';
  9 + import { useDesign } from '/@/hooks/web/useDesign';
  10 + import { itemProps } from '../props';
  11 +
  12 + import MenuContent from '../MenuContent';
  13 + export default defineComponent({
  14 + name: 'BasicMenuItem',
  15 + components: { MenuItem: Menu.Item, MenuContent },
  16 + props: itemProps,
  17 + setup(props) {
  18 + const { prefixCls } = useDesign('basic-menu-item');
  19 +
  20 + const getLevelClass = computed(() => {
  21 + const { appendClass, level, item, parentPath, theme } = props;
  22 + const isAppendActiveCls = appendClass && level === 1 && item.path === parentPath;
  23 +
  24 + const levelCls = [
  25 + `${prefixCls}__level${level}`,
  26 + theme,
  27 + {
  28 + 'top-active-menu': isAppendActiveCls,
  29 + },
  30 + ];
  31 + return levelCls;
  32 + });
  33 + return {
  34 + prefixCls,
  35 + getLevelClass,
  36 + };
  37 + },
  38 + });
  39 +</script>
... ...
src/components/Menu/src/components/BasicSubMenuItem.vue 0 → 100644
  1 +<template>
  2 + <BasicMenuItem v-if="!menuHasChildren(item)" v-bind="$props" />
  3 + <SubMenu v-else :class="[`${prefixCls}__level${level}`, theme]">
  4 + <template #title>
  5 + <MenuContent v-bind="$props" :item="item" />
  6 + </template>
  7 + <!-- <template #expandIcon="{ key }">
  8 + <ExpandIcon :key="key" />
  9 + </template> -->
  10 +
  11 + <template v-for="childrenItem in item.children || []" :key="childrenItem.path">
  12 + <BasicSubMenuItem v-bind="$props" :item="childrenItem" :level="level + 1" />
  13 + </template>
  14 + </SubMenu>
  15 +</template>
  16 +<script lang="ts">
  17 + import type { Menu as MenuType } from '/@/router/types';
  18 +
  19 + import { defineComponent } from 'vue';
  20 + import { Menu } from 'ant-design-vue';
  21 + import { useDesign } from '/@/hooks/web/useDesign';
  22 + import { itemProps } from '../props';
  23 + import BasicMenuItem from './BasicMenuItem.vue';
  24 + import MenuContent from '../MenuContent';
  25 + // import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
  26 +
  27 + export default defineComponent({
  28 + name: 'BasicSubMenuItem',
  29 +
  30 + components: {
  31 + BasicMenuItem,
  32 + SubMenu: Menu.SubMenu,
  33 + MenuItem: Menu.Item,
  34 + MenuContent,
  35 + // ExpandIcon: createAsyncComponent(() => import('./ExpandIcon.vue')),
  36 + },
  37 + props: itemProps,
  38 + setup() {
  39 + const { prefixCls } = useDesign('basic-menu-item');
  40 + function menuHasChildren(menuTreeItem: MenuType): boolean {
  41 + return (
  42 + Reflect.has(menuTreeItem, 'children') &&
  43 + !!menuTreeItem.children &&
  44 + menuTreeItem.children.length > 0
  45 + );
  46 + }
  47 + return {
  48 + prefixCls,
  49 + menuHasChildren,
  50 + };
  51 + },
  52 + });
  53 +</script>
... ...
src/components/Menu/src/components/ExpandIcon.vue 0 → 100644
  1 +<template>
  2 + <BasicArrow :expand="getIsOpen" bottom inset :class="getWrapperClass" />
  3 +</template>
  4 +<script lang="ts">
  5 + import { defineComponent, PropType, computed } from 'vue';
  6 + import { useDesign } from '/@/hooks/web/useDesign';
  7 + import { BasicArrow } from '/@/components/Basic';
  8 +
  9 + import { propTypes } from '/@/utils/propTypes';
  10 + export default defineComponent({
  11 + name: 'BasicMenuItem',
  12 + components: { BasicArrow },
  13 + props: {
  14 + key: propTypes.string,
  15 + openKeys: {
  16 + type: Array as PropType<string[]>,
  17 + default: [],
  18 + },
  19 + collapsed: propTypes.bool,
  20 + },
  21 + setup(props) {
  22 + const { prefixCls } = useDesign('basic-menu');
  23 +
  24 + const getIsOpen = computed(() => {
  25 + return props.openKeys.includes(props.key);
  26 + });
  27 +
  28 + const getWrapperClass = computed(() => {
  29 + return [
  30 + `${prefixCls}__expand-icon`,
  31 + {
  32 + [`${prefixCls}__expand-icon--collapsed`]: props.collapsed,
  33 + },
  34 + ];
  35 + });
  36 + return {
  37 + prefixCls,
  38 + getIsOpen,
  39 + getWrapperClass,
  40 + };
  41 + },
  42 + });
  43 +</script>
... ...
src/components/Menu/src/helper.ts deleted 100644 → 0
1   -import type { Menu as MenuType } from '/@/router/types';
2   -
3   -/**
4   - * @description: Whether the menu has child nodes
5   - */
6   -export function menuHasChildren(menuTreeItem: MenuType): boolean {
7   - return (
8   - Reflect.has(menuTreeItem, 'children') &&
9   - !!menuTreeItem.children &&
10   - menuTreeItem.children.length > 0
11   - );
12   -}
src/components/Menu/src/index.less
... ... @@ -4,6 +4,7 @@
4 4  
5 5 .active-style() {
6 6 color: @white;
  7 + // background: @primary-color !important;
7 8 background: linear-gradient(
8 9 118deg,
9 10 rgba(@primary-color, 0.8),
... ... @@ -27,6 +28,7 @@
27 28 // right: 16px;
28 29 // width: 10px;
29 30 // transform-origin: none;
  31 + // opacity: 0.45;
30 32  
31 33 // span[role='img'] {
32 34 // margin-right: 0;
... ... @@ -52,9 +54,9 @@
52 54 > .ant-menu-item-group-list
53 55 > .ant-menu-submenu
54 56 > .ant-menu-submenu-title,
55   - &.ant-menu-inline-collapsed > .ant-menu-submenu > .ant-menu-submenu-title {
56   - padding-right: 20px !important;
57   - padding-left: 20px !important;
  57 + &.ant-menu-inline-collapsed .ant-menu-submenu-title {
  58 + padding-right: 16px !important;
  59 + padding-left: 16px !important;
58 60 }
59 61 }
60 62  
... ... @@ -87,32 +89,33 @@
87 89 }
88 90 }
89 91  
90   - // .ant-menu-item {
91   - // transition: unset;
92   - // }
  92 + .ant-menu-item {
  93 + transition: unset;
  94 + }
93 95  
94 96 // scrollbar -s tart
95   - &-wrapper {
96   - /* 滚动槽 */
97   - &::-webkit-scrollbar {
98   - width: 5px;
99   - height: 5px;
100   - }
  97 + // &-wrapper {
101 98  
102   - &::-webkit-scrollbar-track {
103   - background: rgba(0, 0, 0, 0);
104   - }
  99 + /* 滚动槽 */
  100 + // &::-webkit-scrollbar {
  101 + // width: 5px;
  102 + // height: 5px;
  103 + // }
105 104  
106   - &::-webkit-scrollbar-thumb {
107   - background: rgba(255, 255, 255, 0.2);
108   - border-radius: 3px;
109   - box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
110   - }
  105 + // &::-webkit-scrollbar-track {
  106 + // background: rgba(0, 0, 0, 0);
  107 + // }
111 108  
112   - ::-webkit-scrollbar-thumb:hover {
113   - background: @border-color-dark;
114   - }
115   - }
  109 + // &::-webkit-scrollbar-thumb {
  110 + // background: rgba(255, 255, 255, 0.2);
  111 + // border-radius: 3px;
  112 + // box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
  113 + // }
  114 +
  115 + // ::-webkit-scrollbar-thumb:hover {
  116 + // background: @border-color-dark;
  117 + // }
  118 + // }
116 119  
117 120 // scrollbar end
118 121  
... ... @@ -225,14 +228,6 @@
225 228 }
226 229 }
227 230  
228   - &:not(.@{basic-menu-prefix-cls}__sidebar-hor).ant-menu-inline-collapsed {
229   - .@{basic-menu-prefix-cls}-item__level1 {
230   - > div {
231   - align-items: center;
232   - }
233   - }
234   - }
235   -
236 231 &.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor):not(.@{basic-menu-prefix-cls}__second) {
237 232 // Reset menu item row height
238 233 .ant-menu-item:not(.@{basic-menu-prefix-cls}-item__level1),
... ... @@ -255,10 +250,6 @@
255 250 background: @sider-dark-bg-color;
256 251 .active-menu-style();
257 252  
258   - // .menu-item-icon.app-iconify {
259   - // display: inline-block !important;
260   - // }
261   -
262 253 .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
263 254 .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
264 255 color: @white;
... ... @@ -304,10 +295,6 @@
304 295 overflow: hidden;
305 296 border-right: none;
306 297  
307   - // .menu-item-icon.app-iconify {
308   - // display: inline-block !important;
309   - // }
310   -
311 298 .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
312 299 .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
313 300 color: @primary-color;
... ... @@ -332,6 +319,7 @@
332 319 align-items: center;
333 320 }
334 321 }
  322 +
335 323 .@{basic-menu-prefix-cls}__tag {
336 324 position: absolute;
337 325 top: calc(50% - 8px);
... ... @@ -368,6 +356,20 @@
368 356 background: @warning-color;
369 357 }
370 358 }
  359 +
  360 + .ant-menu-submenu,
  361 + .ant-menu-submenu-inline {
  362 + transition: unset;
  363 + }
  364 +
  365 + // .ant-menu-submenu-arrow {
  366 + // transition: all 0.15s ease 0s;
  367 + // }
  368 +
  369 + .ant-menu-inline.ant-menu-sub {
  370 + box-shadow: unset !important;
  371 + transition: unset;
  372 + }
371 373 }
372 374  
373 375 .ant-menu-dark {
... ... @@ -375,7 +377,6 @@
375 377 > ul {
376 378 background: @sider-dark-bg-color;
377 379 }
378   -
379 380 .active-menu-style();
380 381 }
381 382 }
... ...
src/components/Menu/src/props.ts
... ... @@ -3,57 +3,47 @@ import type { PropType } from &#39;vue&#39;;
3 3  
4 4 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
5 5 import { ThemeEnum } from '/@/enums/appEnum';
  6 +import { propTypes } from '/@/utils/propTypes';
6 7 export const basicProps = {
7 8 items: {
8 9 type: Array as PropType<Menu[]>,
9 10 default: () => [],
10 11 },
11   - appendClass: {
12   - type: Boolean as PropType<boolean>,
13   - default: false,
14   - },
  12 + appendClass: propTypes.bool,
15 13  
16   - collapsedShowTitle: {
17   - type: Boolean as PropType<boolean>,
18   - default: false,
19   - },
  14 + collapsedShowTitle: propTypes.bool,
20 15  
21 16 // 最好是4 倍数
22   - inlineIndent: {
23   - type: Number as PropType<number>,
24   - default: 20,
25   - },
  17 + inlineIndent: propTypes.number.def(20),
26 18 // 菜单组件的mode属性
27 19 mode: {
28 20 type: String as PropType<MenuModeEnum>,
29 21 default: MenuModeEnum.INLINE,
30 22 },
31   - showLogo: {
32   - type: Boolean as PropType<boolean>,
33   - default: false,
34   - },
  23 + showLogo: propTypes.bool,
35 24 type: {
36 25 type: String as PropType<MenuTypeEnum>,
37 26 default: MenuTypeEnum.MIX,
38 27 },
39   - theme: {
40   - type: String as PropType<string>,
41   - default: ThemeEnum.DARK,
42   - },
43   - inlineCollapsed: {
44   - type: Boolean as PropType<boolean>,
45   - default: false,
46   - },
  28 + theme: propTypes.string.def(ThemeEnum.DARK),
  29 + inlineCollapsed: propTypes.bool,
47 30  
48   - isHorizontal: {
49   - type: Boolean as PropType<boolean>,
50   - default: false,
51   - },
52   - accordion: {
53   - type: Boolean as PropType<boolean>,
54   - default: true,
55   - },
  31 + isHorizontal: propTypes.bool,
  32 + accordion: propTypes.bool.def(true),
56 33 beforeClickFn: {
57 34 type: Function as PropType<(key: string) => Promise<boolean>>,
58 35 },
59 36 };
  37 +
  38 +export const itemProps = {
  39 + item: {
  40 + type: Object as PropType<Menu>,
  41 + default: {},
  42 + },
  43 + level: propTypes.number,
  44 + theme: propTypes.oneOf(['dark', 'light']),
  45 + appendClass: propTypes.bool,
  46 + parentPath: propTypes.string,
  47 + showTitle: propTypes.bool,
  48 + isHorizontal: propTypes.bool,
  49 +};
... ...
src/components/Menu/src/types.ts
1   -import { ComputedRef } from 'vue';
2   -import { ThemeEnum } from '/@/enums/appEnum';
3   -import { MenuModeEnum } from '/@/enums/menuEnum';
  1 +// import { ComputedRef } from 'vue';
  2 +// import { ThemeEnum } from '/@/enums/appEnum';
  3 +// import { MenuModeEnum } from '/@/enums/menuEnum';
4 4 export interface MenuState {
5 5 // 默认选中的列表
6 6 defaultSelectedKeys: string[];
7 7  
8 8 // 模式
9   - mode: MenuModeEnum;
  9 + // mode: MenuModeEnum;
10 10  
11   - // 主题
12   - theme: ComputedRef<ThemeEnum> | ThemeEnum;
  11 + // // 主题
  12 + // theme: ComputedRef<ThemeEnum> | ThemeEnum;
13 13  
14 14 // 缩进
15 15 inlineIndent?: number;
... ...
src/enums/appEnum.ts
1   -export const SIDE_BAR_MINI_WIDTH = 58;
  1 +export const SIDE_BAR_MINI_WIDTH = 48;
2 2 export const SIDE_BAR_SHOW_TIT_MINI_WIDTH = 80;
3 3  
4 4 export enum ContentEnum {
... ...
src/layouts/default/tabs/index.less
... ... @@ -34,9 +34,9 @@
34 34 border: 1px solid darken(@border-color-light, 6%);
35 35 transition: none;
36 36  
37   - &:not(.ant-tabs-tab-active)::before {
  37 + &:not(.ant-tabs-tab-active)::after {
38 38 position: absolute;
39   - top: -1px;
  39 + bottom: -1px;
40 40 left: 50%;
41 41 width: 100%;
42 42 height: 2px;
... ... @@ -53,7 +53,7 @@
53 53 opacity: 1;
54 54 }
55 55  
56   - &:not(.ant-tabs-tab-active)::before {
  56 + &:not(.ant-tabs-tab-active)::after {
57 57 opacity: 1;
58 58 transform: translate(-50%, 0) scaleX(1);
59 59 transition: all 0.3s ease-in-out;
... ...
src/router/helper/menuHelper.ts
... ... @@ -42,6 +42,7 @@ export function transformMenuModule(menuModule: MenuModule): Menu {
42 42 forEach(menuList, (m) => {
43 43 !isUrl(m.path) && joinParentPath(menuList, m);
44 44 });
  45 +
45 46 return menuList[0];
46 47 }
47 48  
... ...