Commit ee1c3498587951a6a4cc0b49edb9dacf3f2af5c3

Authored by Vben
1 parent 780a8a67

fix(menu): improve menu logic, fix #461

CHANGELOG.zh_CN.md
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 ### 🐛 Bug Fixes 3 ### 🐛 Bug Fixes
4 4
5 - 登录页样式修复 5 - 登录页样式修复
  6 +- 修复菜单已知问题
6 7
7 ## 2.2.0 (2021-04-06) 8 ## 2.2.0 (2021-04-06)
8 9
src/components/Application/src/AppDarkModeToggle.vue
@@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
3 v-if="getShowDarkModeToggle" 3 v-if="getShowDarkModeToggle"
4 :class="[ 4 :class="[
5 prefixCls, 5 prefixCls,
6 - `${prefixCls}--${size}`,  
7 { 6 {
8 [`${prefixCls}--dark`]: isDark, 7 [`${prefixCls}--dark`]: isDark,
9 }, 8 },
@@ -30,13 +29,13 @@ @@ -30,13 +29,13 @@
30 export default defineComponent({ 29 export default defineComponent({
31 name: 'DarkModeToggle', 30 name: 'DarkModeToggle',
32 components: { SvgIcon }, 31 components: { SvgIcon },
33 - props: {  
34 - size: {  
35 - type: String,  
36 - default: 'default',  
37 - validate: (val) => ['default', 'large'].includes(val),  
38 - },  
39 - }, 32 + // props: {
  33 + // size: {
  34 + // type: String,
  35 + // default: 'default',
  36 + // validate: (val) => ['default', 'large'].includes(val),
  37 + // },
  38 + // },
40 setup() { 39 setup() {
41 const { prefixCls } = useDesign('dark-mode-toggle'); 40 const { prefixCls } = useDesign('dark-mode-toggle');
42 const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting(); 41 const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
@@ -97,15 +96,15 @@ @@ -97,15 +96,15 @@
97 } 96 }
98 } 97 }
99 98
100 - &--large {  
101 - width: 72px;  
102 - height: 34px;  
103 - padding: 0 10px; 99 + // &--large {
  100 + // width: 70px;
  101 + // height: 34px;
  102 + // padding: 0 10px;
104 103
105 - .@{prefix-cls}-inner {  
106 - width: 26px;  
107 - height: 26px;  
108 - }  
109 - } 104 + // .@{prefix-cls}-inner {
  105 + // width: 26px;
  106 + // height: 26px;
  107 + // }
  108 + // }
110 } 109 }
111 </style> 110 </style>
src/components/Icon/src/index.vue
@@ -24,8 +24,6 @@ @@ -24,8 +24,6 @@
24 import Iconify from '@purge-icons/generated'; 24 import Iconify from '@purge-icons/generated';
25 import { isString } from '/@/utils/is'; 25 import { isString } from '/@/utils/is';
26 import { propTypes } from '/@/utils/propTypes'; 26 import { propTypes } from '/@/utils/propTypes';
27 - import { useRootSetting } from '/@/hooks/setting/useRootSetting';  
28 - import { ThemeEnum } from '/@/enums/appEnum';  
29 27
30 const SVG_END_WITH_FLAG = '|svg'; 28 const SVG_END_WITH_FLAG = '|svg';
31 export default defineComponent({ 29 export default defineComponent({
@@ -46,8 +44,6 @@ @@ -46,8 +44,6 @@
46 setup(props) { 44 setup(props) {
47 const elRef = ref<ElRef>(null); 45 const elRef = ref<ElRef>(null);
48 46
49 - const { getDarkMode } = useRootSetting();  
50 -  
51 const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG)); 47 const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG));
52 const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, '')); 48 const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, ''));
53 const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`); 49 const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`);
@@ -85,7 +81,7 @@ @@ -85,7 +81,7 @@
85 81
86 return { 82 return {
87 fontSize: `${fs}px`, 83 fontSize: `${fs}px`,
88 - color: color || (unref(getDarkMode) === ThemeEnum.DARK ? '#fff' : '#303133'), 84 + color: color,
89 display: 'inline-flex', 85 display: 'inline-flex',
90 }; 86 };
91 } 87 }
src/components/SimpleMenu/src/SimpleMenu.vue
1 <template> 1 <template>
2 <Menu 2 <Menu
3 v-bind="getBindValues" 3 v-bind="getBindValues"
4 - @select="handleSelect"  
5 :activeName="activeName" 4 :activeName="activeName"
6 :openNames="getOpenKeys" 5 :openNames="getOpenKeys"
7 :class="prefixCls" 6 :class="prefixCls"
8 :activeSubMenuNames="activeSubMenuNames" 7 :activeSubMenuNames="activeSubMenuNames"
  8 + @select="handleSelect"
  9 + @open-change="handleOpenChange"
9 > 10 >
10 <template v-for="item in items" :key="item.path"> 11 <template v-for="item in items" :key="item.path">
11 <SimpleSubMenu 12 <SimpleSubMenu
@@ -53,6 +54,7 @@ @@ -53,6 +54,7 @@
53 beforeClickFn: { 54 beforeClickFn: {
54 type: Function as PropType<(key: string) => Promise<boolean>>, 55 type: Function as PropType<(key: string) => Promise<boolean>>,
55 }, 56 },
  57 + isSplitMenu: propTypes.bool,
56 }, 58 },
57 emits: ['menuClick'], 59 emits: ['menuClick'],
58 setup(props, { attrs, emit }) { 60 setup(props, { attrs, emit }) {
@@ -94,6 +96,9 @@ @@ -94,6 +96,9 @@
94 watch( 96 watch(
95 () => props.items, 97 () => props.items,
96 () => { 98 () => {
  99 + if (!props.isSplitMenu) {
  100 + return;
  101 + }
97 setOpenKeys(currentRoute.value.path); 102 setOpenKeys(currentRoute.value.path);
98 }, 103 },
99 { flush: 'post' } 104 { flush: 'post' }
@@ -135,11 +140,17 @@ @@ -135,11 +140,17 @@
135 menuState.activeName = key; 140 menuState.activeName = key;
136 } 141 }
137 142
  143 + function handleOpenChange(v) {
  144 + console.log('======================');
  145 + console.log(v);
  146 + console.log('======================');
  147 + }
138 return { 148 return {
139 prefixCls, 149 prefixCls,
140 getBindValues, 150 getBindValues,
141 handleSelect, 151 handleSelect,
142 getOpenKeys, 152 getOpenKeys,
  153 + handleOpenChange,
143 ...toRefs(menuState), 154 ...toRefs(menuState),
144 }; 155 };
145 }, 156 },
src/components/SimpleMenu/src/components/Menu.vue
@@ -138,6 +138,15 @@ @@ -138,6 +138,15 @@
138 }); 138 });
139 emit('select', name); 139 emit('select', name);
140 }); 140 });
  141 +
  142 + rootMenuEmitter.on('open-name-change', ({ name, opened }) => {
  143 + if (opened && !openedNames.value.includes(name)) {
  144 + openedNames.value.push(name);
  145 + } else if (!opened) {
  146 + const index = openedNames.value.findIndex((item) => item === name);
  147 + index !== -1 && openedNames.value.splice(index, 1);
  148 + }
  149 + });
141 }); 150 });
142 151
143 return { getClass, openedNames }; 152 return { getClass, openedNames };
src/components/SimpleMenu/src/components/MenuItem.vue
@@ -66,11 +66,16 @@ @@ -66,11 +66,16 @@
66 66
67 function handleClickItem() { 67 function handleClickItem() {
68 const { disabled } = props; 68 const { disabled } = props;
69 - if (disabled) return; 69 + if (disabled) {
  70 + return;
  71 + }
70 72
71 rootMenuEmitter.emit('on-menu-item-select', props.name); 73 rootMenuEmitter.emit('on-menu-item-select', props.name);
72 - if (unref(getCollapse)) return; 74 + if (unref(getCollapse)) {
  75 + return;
  76 + }
73 const { uidList } = getParentList(); 77 const { uidList } = getParentList();
  78 +
74 rootMenuEmitter.emit('on-update-opened', { 79 rootMenuEmitter.emit('on-update-opened', {
75 opend: false, 80 opend: false,
76 parent: instance?.parent, 81 parent: instance?.parent,
src/components/SimpleMenu/src/components/SubMenuItem.vue
@@ -43,8 +43,9 @@ @@ -43,8 +43,9 @@
43 :class="`${prefixCls}-submenu-title-icon`" 43 :class="`${prefixCls}-submenu-title-icon`"
44 /> 44 />
45 </div> 45 </div>
46 - <template #content>  
47 - <div v-bind="getEvents(true)" v-show="opened"> 46 + <!-- eslint-disable-next-line -->
  47 + <template #content v-show="opened">
  48 + <div v-bind="getEvents(true)">
48 <ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]"> 49 <ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]">
49 <slot></slot> 50 <slot></slot>
50 </ul> 51 </ul>
@@ -78,7 +79,7 @@ @@ -78,7 +79,7 @@
78 import { isBoolean, isObject } from '/@/utils/is'; 79 import { isBoolean, isObject } from '/@/utils/is';
79 import Mitt from '/@/utils/mitt'; 80 import Mitt from '/@/utils/mitt';
80 81
81 - const DELAY = 250; 82 + const DELAY = 200;
82 export default defineComponent({ 83 export default defineComponent({
83 name: 'SubMenu', 84 name: 'SubMenu',
84 components: { 85 components: {
@@ -189,6 +190,7 @@ @@ -189,6 +190,7 @@
189 const { disabled } = props; 190 const { disabled } = props;
190 if (disabled || unref(getCollapse)) return; 191 if (disabled || unref(getCollapse)) return;
191 const opened = state.opened; 192 const opened = state.opened;
  193 +
192 if (unref(getAccordion)) { 194 if (unref(getAccordion)) {
193 const { uidList } = getParentList(); 195 const { uidList } = getParentList();
194 rootMenuEmitter.emit('on-update-opened', { 196 rootMenuEmitter.emit('on-update-opened', {
@@ -196,6 +198,11 @@ @@ -196,6 +198,11 @@
196 parent: instance?.parent, 198 parent: instance?.parent,
197 uidList: uidList, 199 uidList: uidList,
198 }); 200 });
  201 + } else {
  202 + rootMenuEmitter.emit('open-name-change', {
  203 + name: props.name,
  204 + opened: !opened,
  205 + });
199 } 206 }
200 state.opened = !opened; 207 state.opened = !opened;
201 } 208 }
src/components/SimpleMenu/src/useOpenKeys.ts
@@ -8,7 +8,7 @@ import { uniq } from &#39;lodash-es&#39;; @@ -8,7 +8,7 @@ import { uniq } from &#39;lodash-es&#39;;
8 import { getAllParentPath } from '/@/router/helper/menuHelper'; 8 import { getAllParentPath } from '/@/router/helper/menuHelper';
9 9
10 import { useTimeoutFn } from '/@/hooks/core/useTimeout'; 10 import { useTimeoutFn } from '/@/hooks/core/useTimeout';
11 -import { useDebounce } from '../../../hooks/core/useDebounce'; 11 +import { useDebounce } from '/@/hooks/core/useDebounce';
12 12
13 export function useOpenKeys( 13 export function useOpenKeys(
14 menuState: MenuState, 14 menuState: MenuState,
src/layouts/default/menu/index.vue
@@ -49,6 +49,7 @@ @@ -49,6 +49,7 @@
49 getAccordion, 49 getAccordion,
50 getIsHorizontal, 50 getIsHorizontal,
51 getIsSidebarType, 51 getIsSidebarType,
  52 + getSplit,
52 } = useMenuSetting(); 53 } = useMenuSetting();
53 const { getShowLogo } = useRootSetting(); 54 const { getShowLogo } = useRootSetting();
54 55
@@ -144,7 +145,7 @@ @@ -144,7 +145,7 @@
144 // console.log(menus); 145 // console.log(menus);
145 if (!menus || !menus.length) return null; 146 if (!menus || !menus.length) return null;
146 return !props.isHorizontal ? ( 147 return !props.isHorizontal ? (
147 - <SimpleMenu {...menuProps} items={menus} /> 148 + <SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} />
148 ) : ( 149 ) : (
149 <BasicMenu 150 <BasicMenu
150 {...menuProps} 151 {...menuProps}
src/layouts/default/setting/SettingDrawer.tsx
@@ -408,7 +408,7 @@ export default defineComponent({ @@ -408,7 +408,7 @@ export default defineComponent({
408 wrapClassName="setting-drawer" 408 wrapClassName="setting-drawer"
409 > 409 >
410 {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>} 410 {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
411 - {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" size="large" />} 411 + {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" />}
412 <Divider>{() => t('layout.setting.navMode')}</Divider> 412 <Divider>{() => t('layout.setting.navMode')}</Divider>
413 {renderSidebar()} 413 {renderSidebar()}
414 <Divider>{() => t('layout.setting.sysTheme')}</Divider> 414 <Divider>{() => t('layout.setting.sysTheme')}</Divider>
src/layouts/default/tabs/index.less
@@ -82,7 +82,7 @@ html[data-theme=&#39;dark&#39;] { @@ -82,7 +82,7 @@ html[data-theme=&#39;dark&#39;] {
82 .ant-tabs-tab-active { 82 .ant-tabs-tab-active {
83 position: relative; 83 position: relative;
84 padding-left: 18px; 84 padding-left: 18px;
85 - color: @white; 85 + color: @white !important;
86 background: @primary-color; 86 background: @primary-color;
87 border: 0; 87 border: 0;
88 transition: none; 88 transition: none;
src/router/routes/modules/demo/charts.ts
@@ -7,7 +7,7 @@ const charts: AppRouteModule = { @@ -7,7 +7,7 @@ const charts: AppRouteModule = {
7 path: '/charts', 7 path: '/charts',
8 name: 'Charts', 8 name: 'Charts',
9 component: LAYOUT, 9 component: LAYOUT,
10 - redirect: '/charts/apexChart', 10 + redirect: '/charts/echarts/map',
11 meta: { 11 meta: {
12 icon: 'ion:bar-chart-outline', 12 icon: 'ion:bar-chart-outline',
13 title: t('routes.demo.charts.charts'), 13 title: t('routes.demo.charts.charts'),
src/views/sys/login/Login.vue
@@ -112,6 +112,10 @@ @@ -112,6 +112,10 @@
112 &-form { 112 &-form {
113 background: transparent !important; 113 background: transparent !important;
114 } 114 }
  115 +
  116 + .app-iconify {
  117 + color: #fff;
  118 + }
115 } 119 }
116 } 120 }
117 121