feat: auto activate subMenu on select root menu (#5147)

* feat: auto activate subMenu on click root menu

* fix: prop name fixed

* chore: test and docs update
This commit is contained in:
Netfan 2024-12-16 02:57:50 +08:00 committed by GitHub
parent 22c1f86ca1
commit 2efb5b71c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 56 additions and 3 deletions

View File

@ -217,6 +217,7 @@ const defaultPreferences: Preferences = {
globalSearch: true, globalSearch: true,
}, },
sidebar: { sidebar: {
autoActivateChild: false,
collapsed: false, collapsed: false,
collapsedShowTitle: false, collapsedShowTitle: false,
enable: true, enable: true,

View File

@ -240,6 +240,7 @@ const defaultPreferences: Preferences = {
globalSearch: true, globalSearch: true,
}, },
sidebar: { sidebar: {
autoActivateChild: false,
collapsed: false, collapsed: false,
collapsedShowTitle: false, collapsedShowTitle: false,
enable: true, enable: true,

View File

@ -65,6 +65,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
"globalSearch": true, "globalSearch": true,
}, },
"sidebar": { "sidebar": {
"autoActivateChild": false,
"collapsed": false, "collapsed": false,
"collapsedShowTitle": false, "collapsedShowTitle": false,
"enable": true, "enable": true,

View File

@ -65,6 +65,7 @@ const defaultPreferences: Preferences = {
globalSearch: true, globalSearch: true,
}, },
sidebar: { sidebar: {
autoActivateChild: false,
collapsed: false, collapsed: false,
collapsedShowTitle: false, collapsedShowTitle: false,
enable: true, enable: true,

View File

@ -125,6 +125,8 @@ interface NavigationPreferences {
} }
interface SidebarPreferences { interface SidebarPreferences {
/** 点击目录时自动激活子菜单 */
autoActivateChild: boolean;
/** 侧边栏是否折叠 */ /** 侧边栏是否折叠 */
collapsed: boolean; collapsed: boolean;
/** 侧边栏折叠时是否显示title */ /** 侧边栏折叠时是否显示title */

View File

@ -15,6 +15,9 @@ function useExtraMenu() {
const menus = computed(() => accessStore.accessMenus); const menus = computed(() => accessStore.accessMenus);
/** 记录当前顶级菜单下哪个子菜单最后激活 */
const defaultSubMap = new Map<string, string>();
const route = useRoute(); const route = useRoute();
const extraMenus = ref<MenuRecordRaw[]>([]); const extraMenus = ref<MenuRecordRaw[]>([]);
const sidebarExtraVisible = ref<boolean>(false); const sidebarExtraVisible = ref<boolean>(false);
@ -32,6 +35,12 @@ function useExtraMenu() {
sidebarExtraVisible.value = hasChildren; sidebarExtraVisible.value = hasChildren;
if (!hasChildren) { if (!hasChildren) {
await navigation(menu.path); await navigation(menu.path);
} else if (preferences.sidebar.autoActivateChild) {
await navigation(
defaultSubMap.has(menu.path)
? (defaultSubMap.get(menu.path) as string)
: menu.path,
);
} }
}; };
@ -89,6 +98,7 @@ function useExtraMenu() {
menus.value, menus.value,
currentPath, currentPath,
); );
if (rootMenuPath) defaultSubMap.set(rootMenuPath, currentPath);
extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? ''; extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? '';
extraMenus.value = rootMenu?.children ?? []; extraMenus.value = rootMenu?.children ?? [];
}, },

View File

@ -1,17 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import type { LayoutType } from '@vben/types';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import NumberFieldItem from '../number-field-item.vue'; import NumberFieldItem from '../number-field-item.vue';
import SwitchItem from '../switch-item.vue'; import SwitchItem from '../switch-item.vue';
defineProps<{ disabled: boolean }>(); defineProps<{ currentLayout?: LayoutType; disabled: boolean }>();
const sidebarEnable = defineModel<boolean>('sidebarEnable'); const sidebarEnable = defineModel<boolean>('sidebarEnable');
const sidebarWidth = defineModel<number>('sidebarWidth'); const sidebarWidth = defineModel<number>('sidebarWidth');
const sidebarCollapsedShowTitle = defineModel<boolean>( const sidebarCollapsedShowTitle = defineModel<boolean>(
'sidebarCollapsedShowTitle', 'sidebarCollapsedShowTitle',
); );
const sidebarAutoActivateChild = defineModel<boolean>(
'sidebarAutoActivateChild',
);
const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed'); const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
const sidebarExpandOnHover = defineModel<boolean>('sidebarExpandOnHover');
</script> </script>
<template> <template>
@ -21,12 +27,28 @@ const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
<SwitchItem v-model="sidebarCollapsed" :disabled="!sidebarEnable || disabled"> <SwitchItem v-model="sidebarCollapsed" :disabled="!sidebarEnable || disabled">
{{ $t('preferences.sidebar.collapsed') }} {{ $t('preferences.sidebar.collapsed') }}
</SwitchItem> </SwitchItem>
<SwitchItem
v-model="sidebarExpandOnHover"
:disabled="!sidebarEnable || disabled || !sidebarCollapsed"
:tip="$t('preferences.sidebar.expandOnHoverTip')"
>
{{ $t('preferences.sidebar.expandOnHover') }}
</SwitchItem>
<SwitchItem <SwitchItem
v-model="sidebarCollapsedShowTitle" v-model="sidebarCollapsedShowTitle"
:disabled="!sidebarEnable || disabled || !sidebarCollapsed" :disabled="!sidebarEnable || disabled || !sidebarCollapsed"
> >
{{ $t('preferences.sidebar.collapsedShowTitle') }} {{ $t('preferences.sidebar.collapsedShowTitle') }}
</SwitchItem> </SwitchItem>
<SwitchItem
v-model="sidebarAutoActivateChild"
:disabled="
!sidebarEnable || currentLayout !== 'sidebar-mixed-nav' || disabled
"
:tip="$t('preferences.sidebar.autoActivateChildTip')"
>
{{ $t('preferences.sidebar.autoActivateChild') }}
</SwitchItem>
<NumberFieldItem <NumberFieldItem
v-model="sidebarWidth" v-model="sidebarWidth"
:disabled="!sidebarEnable || disabled" :disabled="!sidebarEnable || disabled"

View File

@ -87,6 +87,10 @@ const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
const sidebarCollapsedShowTitle = defineModel<boolean>( const sidebarCollapsedShowTitle = defineModel<boolean>(
'sidebarCollapsedShowTitle', 'sidebarCollapsedShowTitle',
); );
const sidebarAutoActivateChild = defineModel<boolean>(
'sidebarAutoActivateChild',
);
const SidebarExpandOnHover = defineModel<boolean>('sidebarExpandOnHover');
const headerEnable = defineModel<boolean>('headerEnable'); const headerEnable = defineModel<boolean>('headerEnable');
const headerMode = defineModel<LayoutHeaderModeType>('headerMode'); const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
@ -299,10 +303,13 @@ async function handleReset() {
<Block :title="$t('preferences.sidebar.title')"> <Block :title="$t('preferences.sidebar.title')">
<Sidebar <Sidebar
v-model:sidebar-auto-activate-child="sidebarAutoActivateChild"
v-model:sidebar-collapsed="sidebarCollapsed" v-model:sidebar-collapsed="sidebarCollapsed"
v-model:sidebar-collapsed-show-title="sidebarCollapsedShowTitle" v-model:sidebar-collapsed-show-title="sidebarCollapsedShowTitle"
v-model:sidebar-enable="sidebarEnable" v-model:sidebar-enable="sidebarEnable"
v-model:sidebar-expand-on-hover="SidebarExpandOnHover"
v-model:sidebar-width="sidebarWidth" v-model:sidebar-width="sidebarWidth"
:current-layout="appLayout"
:disabled="!isSideMode" :disabled="!isSideMode"
/> />
</Block> </Block>

View File

@ -45,7 +45,11 @@
"width": "Width", "width": "Width",
"visible": "Show Sidebar", "visible": "Show Sidebar",
"collapsed": "Collpase Menu", "collapsed": "Collpase Menu",
"collapsedShowTitle": "Show Menu Title" "collapsedShowTitle": "Show Menu Title",
"autoActivateChild": "Auto Activate SubMenu",
"autoActivateChildTip": "`Enabled` to automatically activate the submenu while click menu.",
"expandOnHover": "Expand On Hover",
"expandOnHoverTip": "When the mouse hovers over menu, \n `Enabled` to expand children menus \n `Disabled` to expand whole sidebar."
}, },
"tabbar": { "tabbar": {
"title": "Tabbar", "title": "Tabbar",

View File

@ -45,7 +45,11 @@
"width": "宽度", "width": "宽度",
"visible": "显示侧边栏", "visible": "显示侧边栏",
"collapsed": "折叠菜单", "collapsed": "折叠菜单",
"collapsedShowTitle": "折叠显示菜单名" "collapsedShowTitle": "折叠显示菜单名",
"autoActivateChild": "自动激活子菜单",
"autoActivateChildTip": "点击顶层菜单时,自动激活第一个子菜单或者上一次激活的子菜单",
"expandOnHover": "鼠标悬停展开",
"expandOnHoverTip": "鼠标在折叠区域悬浮时,`启用`则展开当前子菜单,`禁用`则展开整个侧边栏"
}, },
"tabbar": { "tabbar": {
"title": "标签栏", "title": "标签栏",