Commit cbcd9098671e2fff9152976b7e9e815fea29d074

Authored by vben
1 parent f81c4019

wip(menu): perf menu

src/components/Application/src/AppLogo.vue
@@ -66,8 +66,9 @@ @@ -66,8 +66,9 @@
66 .@{prefix-cls} { 66 .@{prefix-cls} {
67 display: flex; 67 display: flex;
68 align-items: center; 68 align-items: center;
69 - padding-left: 12px; 69 + padding-left: 7px;
70 cursor: pointer; 70 cursor: pointer;
  71 + transition: all 0.2s ease;
71 72
72 &.collapsed-show-title { 73 &.collapsed-show-title {
73 padding-left: 20px; 74 padding-left: 20px;
src/components/Menu/index.ts
@@ -2,6 +2,8 @@ import { withInstall } from '../util'; @@ -2,6 +2,8 @@ import { withInstall } from '../util';
2 2
3 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; 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 withInstall(BasicMenu); 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,6 +4,7 @@
4 4
5 .active-style() { 5 .active-style() {
6 color: @white; 6 color: @white;
  7 + // background: @primary-color !important;
7 background: linear-gradient( 8 background: linear-gradient(
8 118deg, 9 118deg,
9 rgba(@primary-color, 0.8), 10 rgba(@primary-color, 0.8),
@@ -27,6 +28,7 @@ @@ -27,6 +28,7 @@
27 // right: 16px; 28 // right: 16px;
28 // width: 10px; 29 // width: 10px;
29 // transform-origin: none; 30 // transform-origin: none;
  31 + // opacity: 0.45;
30 32
31 // span[role='img'] { 33 // span[role='img'] {
32 // margin-right: 0; 34 // margin-right: 0;
@@ -52,9 +54,9 @@ @@ -52,9 +54,9 @@
52 > .ant-menu-item-group-list 54 > .ant-menu-item-group-list
53 > .ant-menu-submenu 55 > .ant-menu-submenu
54 > .ant-menu-submenu-title, 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,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 // scrollbar -s tart 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 // scrollbar end 120 // scrollbar end
118 121
@@ -225,14 +228,6 @@ @@ -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 &.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor):not(.@{basic-menu-prefix-cls}__second) { 231 &.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor):not(.@{basic-menu-prefix-cls}__second) {
237 // Reset menu item row height 232 // Reset menu item row height
238 .ant-menu-item:not(.@{basic-menu-prefix-cls}-item__level1), 233 .ant-menu-item:not(.@{basic-menu-prefix-cls}-item__level1),
@@ -255,10 +250,6 @@ @@ -255,10 +250,6 @@
255 background: @sider-dark-bg-color; 250 background: @sider-dark-bg-color;
256 .active-menu-style(); 251 .active-menu-style();
257 252
258 - // .menu-item-icon.app-iconify {  
259 - // display: inline-block !important;  
260 - // }  
261 -  
262 .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1, 253 .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
263 .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 { 254 .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
264 color: @white; 255 color: @white;
@@ -304,10 +295,6 @@ @@ -304,10 +295,6 @@
304 overflow: hidden; 295 overflow: hidden;
305 border-right: none; 296 border-right: none;
306 297
307 - // .menu-item-icon.app-iconify {  
308 - // display: inline-block !important;  
309 - // }  
310 -  
311 .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1, 298 .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
312 .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 { 299 .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
313 color: @primary-color; 300 color: @primary-color;
@@ -332,6 +319,7 @@ @@ -332,6 +319,7 @@
332 align-items: center; 319 align-items: center;
333 } 320 }
334 } 321 }
  322 +
335 .@{basic-menu-prefix-cls}__tag { 323 .@{basic-menu-prefix-cls}__tag {
336 position: absolute; 324 position: absolute;
337 top: calc(50% - 8px); 325 top: calc(50% - 8px);
@@ -368,6 +356,20 @@ @@ -368,6 +356,20 @@
368 background: @warning-color; 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 .ant-menu-dark { 375 .ant-menu-dark {
@@ -375,7 +377,6 @@ @@ -375,7 +377,6 @@
375 > ul { 377 > ul {
376 background: @sider-dark-bg-color; 378 background: @sider-dark-bg-color;
377 } 379 }
378 -  
379 .active-menu-style(); 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,57 +3,47 @@ import type { PropType } from &#39;vue&#39;;
3 3
4 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; 4 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
5 import { ThemeEnum } from '/@/enums/appEnum'; 5 import { ThemeEnum } from '/@/enums/appEnum';
  6 +import { propTypes } from '/@/utils/propTypes';
6 export const basicProps = { 7 export const basicProps = {
7 items: { 8 items: {
8 type: Array as PropType<Menu[]>, 9 type: Array as PropType<Menu[]>,
9 default: () => [], 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 // 最好是4 倍数 16 // 最好是4 倍数
22 - inlineIndent: {  
23 - type: Number as PropType<number>,  
24 - default: 20,  
25 - }, 17 + inlineIndent: propTypes.number.def(20),
26 // 菜单组件的mode属性 18 // 菜单组件的mode属性
27 mode: { 19 mode: {
28 type: String as PropType<MenuModeEnum>, 20 type: String as PropType<MenuModeEnum>,
29 default: MenuModeEnum.INLINE, 21 default: MenuModeEnum.INLINE,
30 }, 22 },
31 - showLogo: {  
32 - type: Boolean as PropType<boolean>,  
33 - default: false,  
34 - }, 23 + showLogo: propTypes.bool,
35 type: { 24 type: {
36 type: String as PropType<MenuTypeEnum>, 25 type: String as PropType<MenuTypeEnum>,
37 default: MenuTypeEnum.MIX, 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 beforeClickFn: { 33 beforeClickFn: {
57 type: Function as PropType<(key: string) => Promise<boolean>>, 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 export interface MenuState { 4 export interface MenuState {
5 // 默认选中的列表 5 // 默认选中的列表
6 defaultSelectedKeys: string[]; 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 inlineIndent?: number; 15 inlineIndent?: number;
src/enums/appEnum.ts
1 -export const SIDE_BAR_MINI_WIDTH = 58; 1 +export const SIDE_BAR_MINI_WIDTH = 48;
2 export const SIDE_BAR_SHOW_TIT_MINI_WIDTH = 80; 2 export const SIDE_BAR_SHOW_TIT_MINI_WIDTH = 80;
3 3
4 export enum ContentEnum { 4 export enum ContentEnum {
src/layouts/default/tabs/index.less
@@ -34,9 +34,9 @@ @@ -34,9 +34,9 @@
34 border: 1px solid darken(@border-color-light, 6%); 34 border: 1px solid darken(@border-color-light, 6%);
35 transition: none; 35 transition: none;
36 36
37 - &:not(.ant-tabs-tab-active)::before { 37 + &:not(.ant-tabs-tab-active)::after {
38 position: absolute; 38 position: absolute;
39 - top: -1px; 39 + bottom: -1px;
40 left: 50%; 40 left: 50%;
41 width: 100%; 41 width: 100%;
42 height: 2px; 42 height: 2px;
@@ -53,7 +53,7 @@ @@ -53,7 +53,7 @@
53 opacity: 1; 53 opacity: 1;
54 } 54 }
55 55
56 - &:not(.ant-tabs-tab-active)::before { 56 + &:not(.ant-tabs-tab-active)::after {
57 opacity: 1; 57 opacity: 1;
58 transform: translate(-50%, 0) scaleX(1); 58 transform: translate(-50%, 0) scaleX(1);
59 transition: all 0.3s ease-in-out; 59 transition: all 0.3s ease-in-out;
src/router/helper/menuHelper.ts
@@ -42,6 +42,7 @@ export function transformMenuModule(menuModule: MenuModule): Menu { @@ -42,6 +42,7 @@ export function transformMenuModule(menuModule: MenuModule): Menu {
42 forEach(menuList, (m) => { 42 forEach(menuList, (m) => {
43 !isUrl(m.path) && joinParentPath(menuList, m); 43 !isUrl(m.path) && joinParentPath(menuList, m);
44 }); 44 });
  45 +
45 return menuList[0]; 46 return menuList[0];
46 } 47 }
47 48