perf: perf menu

This commit is contained in:
vben
2020-12-07 22:18:57 +08:00
parent 74e62cbc71
commit 88f4a3f02a
24 changed files with 634 additions and 656 deletions

View File

@@ -8,10 +8,10 @@
:dropMenuList="localeList"
:selectedKeys="selectedKeys"
@menuEvent="handleMenuEvent"
overlayClassName="app-locale-picker-overlay"
:overlayClassName="`${prefixCls}-overlay`"
>
<span class="app-local-picker">
<GlobalOutlined class="app-local-picker__icon" />
<span :class="prefixCls">
<GlobalOutlined :class="`${prefixCls}__icon`" />
<span v-if="showText">{{ getLangText }}</span>
</span>
</Dropdown>
@@ -28,6 +28,7 @@
import { LocaleType } from '/@/locales/types';
import { propTypes } from '/@/utils/propTypes';
import { useDesign } from '/@/hooks/web/useDesign';
export default defineComponent({
name: 'AppLocalPicker',
@@ -39,9 +40,12 @@
reload: propTypes.bool,
},
setup(props) {
const { localeList } = useLocaleSetting();
const selectedKeys = ref<string[]>([]);
const { prefixCls } = useDesign('app-locale-picker');
const { localeList } = useLocaleSetting();
const { changeLocale, getLang } = useLocale();
const getLangText = computed(() => {
@@ -64,19 +68,22 @@
toggleLocale(menu.event as string);
}
return { localeList, handleMenuEvent, selectedKeys, getLangText };
return { localeList, handleMenuEvent, selectedKeys, getLangText, prefixCls };
},
});
</script>
<style lang="less" scoped>
:global(.app-locale-picker-overlay) {
@import (reference) '../../../design/index.less';
@prefix-cls: ~'@{namespace}-app-locale-picker';
:global(.@{prefix-cls}-overlay) {
.ant-dropdown-menu-item {
min-width: 160px;
}
}
.app-local-picker {
.@{prefix-cls} {
display: flex;
align-items: center;
cursor: pointer;

View File

@@ -20,15 +20,17 @@
expand: propTypes.bool,
top: propTypes.bool,
bottom: propTypes.bool,
inset: propTypes.bool,
},
setup(props) {
const getClass = computed(() => {
const { expand, top, bottom } = props;
const { expand, top, bottom, inset } = props;
return [
'base-arrow',
{
'base-arrow__active': expand,
top,
inset,
bottom,
},
];
@@ -47,6 +49,10 @@
transition: all 0.3s ease 0.1s;
transform-origin: center center;
&.inset {
line-height: 0px;
}
&__active {
transform: rotate(90deg);
}

View File

@@ -9,14 +9,15 @@ import {
unref,
reactive,
watch,
onMounted,
ref,
toRefs,
ComputedRef,
ref,
CSSProperties,
} from 'vue';
import { Menu } from 'ant-design-vue';
import MenuContent from './MenuContent';
// import { ScrollContainer } from '/@/components/Container';
// import { BasicArrow } from '/@/components/Basic';
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { ThemeEnum } from '/@/enums/appEnum';
@@ -29,18 +30,20 @@ import { useRouter } from 'vue-router';
import { isFunction } from '/@/utils/is';
import { getSlot } from '/@/utils/helper/tsxHelper';
import { menuHasChildren } from './helper';
import { getCurrentParentPath } from '/@/router/menus';
import { basicProps } from './props';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { REDIRECT_NAME } from '/@/router/constant';
import { tabStore } from '/@/store/modules/tab';
import { useDesign } from '/@/hooks/web/useDesign';
export default defineComponent({
name: 'BasicMenu',
props: basicProps,
emits: ['menuClick'],
setup(props, { slots, emit }) {
const currentParentPath = ref('');
const isClickGo = ref(false);
const menuState = reactive<MenuState>({
defaultSelectedKeys: [],
@@ -51,170 +54,184 @@ export default defineComponent({
collapsedOpenKeys: [],
});
const { getCollapsed } = useMenuSetting();
const { prefixCls } = useDesign('basic-menu');
const { items, mode, accordion } = toRefs(props);
const { getCollapsed, getIsHorizontal, getTopMenuAlign, getSplit } = useMenuSetting();
const { currentRoute } = useRouter();
const { items, flatItems, mode, accordion } = toRefs(props);
const { handleOpenChange, resetKeys, setOpenKeys } = useOpenKeys(
const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(
menuState,
items,
flatItems,
mode,
accordion
);
const getOpenKeys = computed(() => {
return unref(getCollapsed) ? menuState.collapsedOpenKeys : menuState.openKeys;
});
// menu外层样式
const getMenuWrapStyle = computed((): any => {
const { showLogo } = props;
let offset = 0;
if (showLogo) {
offset += 46;
}
return {
height: `calc(100% - ${offset}px)`,
position: 'relative',
overflowY: 'auto',
};
});
// 是否透明化左侧一级菜单
const transparentMenuClass = computed(() => {
const getMenuClass = computed(() => {
const { type } = props;
const { mode } = menuState;
const cls: string[] = [];
if (
(type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL) ||
props.appendClass
) {
cls.push('basic-menu__sidebar-hor');
}
if (!props.isHorizontal && appStore.getProjectConfig.menuSetting.split) {
cls.push('basic-menu__second');
}
return cls;
return [
prefixCls,
`justify-${unref(getTopMenuAlign)}`,
{
[`${prefixCls}--hide-title`]: !unref(showTitle),
[`${prefixCls}--collapsed-show-title`]: props.collapsedShowTitle,
[`${prefixCls}__second`]:
!props.isHorizontal && appStore.getProjectConfig.menuSetting.split,
[`${prefixCls}__sidebar-hor`]:
type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL,
},
];
});
const showTitle = computed(() => props.collapsedShowTitle && unref(getCollapsed));
const getInlineCollapseOptions = computed(() => {
const isInline = props.mode === MenuModeEnum.INLINE;
const inlineCollapseOptions: { inlineCollapsed?: boolean } = {};
if (isInline) {
inlineCollapseOptions.inlineCollapsed = unref(getCollapsed);
}
return inlineCollapseOptions;
});
const getWrapperStyle = computed(
(): CSSProperties => {
const isHorizontal = unref(getIsHorizontal);
return {
height: isHorizontal
? `calc(100% + 1px)`
: `calc(100% - ${props.showLogo ? '48px' : '0'})`,
overflowY: isHorizontal ? 'hidden' : 'auto',
};
}
);
watch(
() => currentRoute.value.name,
(name: string) => {
if (name === REDIRECT_NAME) return;
() => tabStore.getCurrentTab,
() => {
if (unref(currentRoute).name === REDIRECT_NAME) return;
handleMenuChange();
props.isHorizontal && appStore.getProjectConfig.menuSetting.split && getParentPath();
unref(getSplit) && getParentPath();
}
);
watch(
() => props.items,
() => {
if (props.items) {
handleMenuChange();
}
handleMenuChange();
},
{
immediate: true,
}
);
getParentPath();
async function getParentPath() {
const { appendClass } = props;
if (!appendClass) return '';
const parentPath = await getCurrentParentPath(unref(currentRoute).path);
currentParentPath.value = parentPath;
}
async function handleMenuClick(menu: MenuType) {
async function handleMenuClick({ key, keyPath }: { key: string; keyPath: string[] }) {
const { beforeClickFn } = props;
if (beforeClickFn && isFunction(beforeClickFn)) {
const flag = await beforeClickFn(menu);
const flag = await beforeClickFn(key);
if (!flag) return;
}
emit('menuClick', menu);
const { path } = menu;
menuState.selectedKeys = [path];
emit('menuClick', key);
isClickGo.value = true;
menuState.openKeys = keyPath;
menuState.selectedKeys = [key];
}
function handleMenuChange() {
const { flatItems } = props;
if (!unref(flatItems) || flatItems.length === 0) return;
const findMenu = flatItems.find((menu) => menu.path === unref(currentRoute).path);
if (findMenu) {
if (menuState.mode !== MenuModeEnum.HORIZONTAL) {
setOpenKeys(findMenu);
}
menuState.selectedKeys = [findMenu.path];
} else {
resetKeys();
if (unref(isClickGo)) {
isClickGo.value = false;
return;
}
const path = unref(currentRoute).path;
if (menuState.mode !== MenuModeEnum.HORIZONTAL) {
setOpenKeys(path);
}
menuState.selectedKeys = [path];
}
// render menu item
function renderMenuItem(menuList?: MenuType[], index = 1) {
if (!menuList) return;
const { appendClass } = props;
const levelCls = `basic-menu-item__level${index} ${menuState.theme} `;
return menuList.map((menu) => {
if (!menu) {
return null;
}
// function renderExpandIcon({ key }: { key: string }) {
// const isOpen = getOpenKeys.value.includes(key);
// const collapsed = unref(getCollapsed);
// return (
// <BasicArrow
// expand={isOpen}
// bottom
// inset
// class={[
// `${prefixCls}__expand-icon`,
// {
// [`${prefixCls}__expand-icon--collapsed`]: collapsed,
// },
// ]}
// />
// );
// }
const isAppendActiveCls =
appendClass && index === 1 && menu.path === unref(currentParentPath);
// 没有子节点
if (!menuHasChildren(menu)) {
return (
<Menu.Item
key={menu.path}
class={`${levelCls}${isAppendActiveCls ? ' top-active-menu ' : ''}`}
onClick={handleMenuClick.bind(null, menu)}
>
{() => [
<MenuContent
item={menu}
level={index}
isHorizontal={props.isHorizontal}
showTitle={unref(showTitle)}
/>,
]}
</Menu.Item>
);
}
return (
<Menu.SubMenu key={menu.path} class={levelCls}>
{{
title: () => [
<MenuContent
showTitle={unref(showTitle)}
item={menu}
level={index}
isHorizontal={props.isHorizontal}
/>,
],
default: () => renderMenuItem(menu.children, index + 1),
}}
</Menu.SubMenu>
);
});
function renderItem(menu: MenuType, level = 1) {
return !menuHasChildren(menu) ? renderMenuItem(menu, level) : renderSubMenu(menu, level);
}
function renderMenuItem(menu: MenuType, level: number) {
const { appendClass } = props;
const isAppendActiveCls =
appendClass && level === 1 && menu.path === unref(currentParentPath);
const levelCls = [
`${prefixCls}-item__level${level}`,
` ${menuState.theme} `,
{
'top-active-menu': isAppendActiveCls,
},
];
return (
<Menu.Item key={menu.path} class={levelCls}>
{() => [
<MenuContent
item={menu}
showTitle={unref(showTitle)}
isHorizontal={props.isHorizontal}
/>,
]}
</Menu.Item>
);
}
function renderSubMenu(menu: MenuType, level: number) {
const levelCls = `${prefixCls}-item__level${level} ${menuState.theme} `;
return (
<Menu.SubMenu key={menu.path} class={levelCls}>
{{
title: () => [
<MenuContent
showTitle={unref(showTitle)}
item={menu}
isHorizontal={props.isHorizontal}
/>,
],
// expandIcon: renderExpandIcon,
default: () => (menu.children || []).map((item) => renderItem(item, level + 1)),
}}
</Menu.SubMenu>
);
}
function renderMenu() {
const isInline = props.mode === MenuModeEnum.INLINE;
const { selectedKeys, defaultSelectedKeys, mode, theme } = menuState;
const inlineCollapsedObj = isInline
? {
inlineCollapsed: unref(getCollapsed),
}
: {};
return (
<Menu
selectedKeys={selectedKeys}
@@ -224,36 +241,25 @@ export default defineComponent({
inlineIndent={props.inlineIndent}
theme={unref(theme)}
onOpenChange={handleOpenChange}
class={[
'basic-menu',
props.collapsedShowTitle && 'collapsed-show-title',
...unref(transparentMenuClass),
]}
{...inlineCollapsedObj}
class={unref(getMenuClass)}
onClick={handleMenuClick}
{...unref(getInlineCollapseOptions)}
>
{{
default: () => renderMenuItem(props.items, 1),
default: () => unref(items).map((item) => renderItem(item)),
}}
</Menu>
);
}
onMounted(async () => {
getParentPath();
});
return () => {
const { mode } = props;
return mode === MenuModeEnum.HORIZONTAL ? (
renderMenu()
) : (
<section class={[`basic-menu-wrap`, !unref(showTitle) && 'hide-title']}>
{getSlot(slots, 'header')}
<section style={unref(getMenuWrapStyle)} class="basic-menu__content">
return (
<>
{!unref(getIsHorizontal) && getSlot(slots, 'header')}
<div class={`${prefixCls}-wrapper`} style={unref(getWrapperStyle)}>
{renderMenu()}
</section>
</section>
</div>
</>
);
};
},

View File

@@ -1,11 +0,0 @@
<template>
<div> </div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
setup() {
return {};
},
});
</script>

View File

@@ -1,9 +1,13 @@
import type { Menu as MenuType } from '/@/router/types';
import { computed, PropType, unref } from 'vue';
import type { PropType } from 'vue';
import { computed, unref } from 'vue';
import { defineComponent } from 'vue';
import Icon from '/@/components/Icon/index';
import { useI18n } from '/@/hooks/web/useI18n';
import { useDesign } from '/@/hooks/web/useDesign';
const { t } = useI18n();
export default defineComponent({
name: 'MenuContent',
@@ -12,12 +16,10 @@ export default defineComponent({
type: Object as PropType<MenuType>,
default: null,
},
showTitle: {
type: Boolean as PropType<boolean>,
default: true,
},
level: {
type: Number as PropType<number>,
default: 0,
@@ -28,13 +30,32 @@ export default defineComponent({
},
},
setup(props) {
const { t } = useI18n();
const { prefixCls } = useDesign('basic-menu');
const getI18nName = computed(() => t(props.item?.name));
const getTagClass = computed(() => {
const { item } = props;
const { tag = {} } = item || {};
const { dot, type = 'error' } = tag;
return [
`${prefixCls}__tag`,
type,
{
dot,
},
];
});
const getNameClass = computed(() => {
const { showTitle } = props;
return { [`${prefixCls}--show-title`]: showTitle, [`${prefixCls}__name`]: !showTitle };
});
/**
* @description: 渲染图标
*/
function renderIcon(icon: string) {
function renderIcon(icon?: string) {
return icon ? <Icon icon={icon} size={18} class="menu-item-icon" /> : null;
}
@@ -45,36 +66,30 @@ export default defineComponent({
const { tag } = item;
if (!tag) return null;
const { dot, content, type = 'error' } = tag;
const { dot, content } = tag;
if (!dot && !content) return null;
const cls = ['basic-menu__tag'];
dot && cls.push('dot');
type && cls.push(type);
return <span class={cls}>{dot ? '' : content}</span>;
return <span class={unref(getTagClass)}>{dot ? '' : content}</span>;
}
return () => {
if (!props.item) {
const { item } = props;
if (!item) {
return null;
}
const { showTitle } = props;
const { icon } = props.item;
const { icon } = item;
const name = unref(getI18nName);
const cls = showTitle ? ['show-title'] : ['basic-menu__name'];
return (
<>
{renderIcon(icon!)}
<span class={`${prefixCls}__content-wrapper`}>
{renderIcon(icon)}
{
<span class={[cls]}>
<span class={unref(getNameClass)}>
{name}
{renderTag()}
</span>
}
</>
</span>
);
};
},

View File

@@ -1,5 +1,7 @@
@import (reference) '../../../design/index.less';
@basic-menu-prefix-cls: ~'@{namespace}-basic-menu';
.active-style() {
color: @white;
background: linear-gradient(
@@ -16,21 +18,48 @@
}
}
.basic-menu {
.@{basic-menu-prefix-cls} {
width: 100%;
&-wrap {
height: 100%;
}
// &__expand-icon {
// position: absolute;
// top: calc(50% - 6px);
// right: 16px;
// width: 10px;
// transform-origin: none;
// span[role='img'] {
// margin-right: 0;
// font-size: 11px;
// }
// &--collapsed {
// opacity: 0;
// }
// }
// collapsed show title start
.show-title {
&--show-title {
max-width: unset !important;
opacity: 1 !important;
}
&.collapsed-show-title.ant-menu-inline-collapsed {
.basic-menu-item__level1 {
&--hide-title {
&.ant-menu-inline-collapsed > .ant-menu-item,
&.ant-menu-inline-collapsed > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,
&.ant-menu-inline-collapsed
> .ant-menu-item-group
> .ant-menu-item-group-list
> .ant-menu-submenu
> .ant-menu-submenu-title,
&.ant-menu-inline-collapsed > .ant-menu-submenu > .ant-menu-submenu-title {
padding-right: 20px !important;
padding-left: 20px !important;
}
}
&--collapsed-show-title.ant-menu-inline-collapsed {
.@{basic-menu-prefix-cls}-item__level1 {
padding: 2px 0;
}
@@ -47,14 +76,23 @@
& > li > .ant-menu-submenu-title {
line-height: 24px;
}
.@{basic-menu-prefix-cls}__content-wrapper {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.@{basic-menu-prefix-cls}--show-title {
line-height: 30px;
}
}
}
.ant-menu-item {
transition: unset;
}
// .ant-menu-item {
// transition: unset;
// }
// scrollbar -s tart
&__content {
&-wrapper {
/* 滚动槽 */
&::-webkit-scrollbar {
width: 5px;
@@ -75,8 +113,20 @@
background: @border-color-dark;
}
}
// scrollbar end
&-item__level1.light {
&.top-active-menu {
top: 0 !important;
}
&.top-active-menu:not(.ant-menu-item-selected) {
color: @primary-color;
border-bottom: 3px solid @primary-color;
}
}
&__sidebar-hor {
// overflow: hidden;
@@ -85,20 +135,13 @@
border: 0;
align-items: center;
.basic-menu-item__level1 {
.@{basic-menu-prefix-cls}-item__level1 {
margin-right: 2px;
}
&.ant-menu-light {
.basic-menu-item__level1 {
&.top-active-menu {
color: @primary-color;
border-bottom: 3px solid @primary-color;
}
}
.ant-menu-item {
&.basic-menu-item__level1 {
&.@{basic-menu-prefix-cls}-item__level1 {
height: @header-height;
line-height: @header-height;
}
@@ -155,7 +198,7 @@
background: @top-menu-active-bg-color;
}
.basic-menu-item__level1 {
.@{basic-menu-prefix-cls}-item__level1 {
background: transparent;
&.top-active-menu {
@@ -172,7 +215,7 @@
.ant-menu-item,
.ant-menu-submenu {
&.basic-menu-item__level1,
&.@{basic-menu-prefix-cls}-item__level1,
.ant-menu-submenu-title {
height: @header-height;
line-height: @header-height;
@@ -182,17 +225,17 @@
}
}
&:not(.basic-menu__sidebar-hor).ant-menu-inline-collapsed {
.basic-menu-item__level1 {
&:not(.@{basic-menu-prefix-cls}__sidebar-hor).ant-menu-inline-collapsed {
.@{basic-menu-prefix-cls}-item__level1 {
> div {
align-items: center;
}
}
}
&.ant-menu-dark:not(.basic-menu__sidebar-hor):not(.basic-menu__second) {
&.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor):not(.@{basic-menu-prefix-cls}__second) {
// Reset menu item row height
.ant-menu-item:not(.basic-menu-item__level1),
.ant-menu-item:not(.@{basic-menu-prefix-cls}-item__level1),
.ant-menu-sub.ant-menu-inline > .ant-menu-item,
.ant-menu-sub.ant-menu-inline > .ant-menu-submenu > .ant-menu-submenu-title {
height: @app-menu-item-height;
@@ -200,28 +243,28 @@
line-height: @app-menu-item-height;
}
.ant-menu-item.basic-menu-item__level1 {
.ant-menu-item.@{basic-menu-prefix-cls}-item__level1 {
height: @app-menu-item-height;
line-height: @app-menu-item-height;
}
}
// 层级样式
&.ant-menu-dark:not(.basic-menu__sidebar-hor) {
overflow-x: hidden;
&.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
overflow: hidden;
background: @sider-dark-bg-color;
.active-menu-style();
.menu-item-icon.app-iconify {
display: inline-block !important;
}
// .menu-item-icon.app-iconify {
// display: inline-block !important;
// }
.ant-menu-item.ant-menu-item-selected.basic-menu-menu-item__level1,
.ant-menu-submenu-selected.basic-menu-menu-item__level1 {
.ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
.ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
color: @white;
}
.basic-menu-item__level1 {
.@{basic-menu-prefix-cls}-item__level1 {
background-color: @sider-dark-bg-color;
> .ant-menu-sub > li {
@@ -229,12 +272,12 @@
}
}
.basic-menu-item__level2:not(.ant-menu-item-selected),
.@{basic-menu-prefix-cls}-item__level2:not(.ant-menu-item-selected),
.ant-menu-sub {
background-color: @sider-dark-lighten-1-bg-color;
}
.basic-menu-item__level3:not(.ant-menu-item-selected) {
.@{basic-menu-prefix-cls}-item__level3:not(.ant-menu-item-selected) {
background-color: @sider-dark-lighten-2-bg-color;
.ant-menu-item {
@@ -257,35 +300,26 @@
}
}
&.ant-menu-light:not(.basic-menu__sidebar-hor) {
overflow-x: hidden;
&.ant-menu-light:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
overflow: hidden;
border-right: none;
.menu-item-icon.app-iconify {
display: inline-block !important;
}
// .ant-menu-item-selected {
// background: fade(@primary-color, 18%);
// .menu-item-icon.app-iconify {
// display: inline-block !important;
// }
.ant-menu-item.ant-menu-item-selected.basic-menu-menu-item__level1,
.ant-menu-submenu-selected.basic-menu-menu-item__level1 {
.ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
.ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
color: @primary-color;
}
}
// 关键字的颜色
&__keyword {
color: lighten(@primary-color, 20%);
}
// 激活的子菜单样式
.ant-menu-item.ant-menu-item-selected {
position: relative;
}
&.basic-menu__second.ant-menu-inline-collapsed:not(.basic-menu__sidebar-hor) {
&.@{basic-menu-prefix-cls}__second.ant-menu-inline-collapsed:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
// Reset menu item row height
.ant-menu-item,
.ant-menu-sub.ant-menu-inline > .ant-menu-item,
@@ -298,26 +332,40 @@
align-items: center;
}
}
}
.@{basic-menu-prefix-cls}__tag {
position: absolute;
top: calc(50% - 8px);
right: 30px;
display: inline-block;
padding: 2px 4px;
margin-right: 4px;
font-size: 12px;
line-height: 14px;
color: #fff;
border-radius: 2px;
// 触发器样式
.ant-layout-sider {
&-dark {
.ant-layout-sider-trigger {
color: darken(@white, 25%);
background: @trigger-dark-bg-color;
&:hover {
color: @white;
background: @trigger-dark-hover-bg-color;
}
&.dot {
top: calc(50% - 4px);
width: 8px;
height: 8px;
padding: 0;
border-radius: 50%;
}
}
&-light {
.ant-layout-sider-trigger {
color: @text-color-base;
border-top: 1px solid @border-color-light;
&.primary {
background: @primary-color;
}
&.error {
background: @error-color;
}
&.success {
background: @success-color;
}
&.warn {
background: @warning-color;
}
}
}
@@ -332,71 +380,16 @@
}
}
.hide-title {
.ant-menu-inline-collapsed > .ant-menu-item,
.ant-menu-inline-collapsed > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,
.ant-menu-inline-collapsed
> .ant-menu-item-group
> .ant-menu-item-group-list
> .ant-menu-submenu
> .ant-menu-submenu-title,
.ant-menu-inline-collapsed > .ant-menu-submenu > .ant-menu-submenu-title {
padding-right: 20px !important;
padding-left: 20px !important;
}
.ant-menu-inline-collapsed {
.basic-menu-item__level1 {
display: flex;
justify-content: center;
}
}
}
// collapsed show title end
.ant-menu-item,
.ant-menu-submenu-title {
> .basic-menu__name {
> .@{basic-menu-prefix-cls}__name {
width: 100%;
.basic-menu__tag {
.@{basic-menu-prefix-cls}__tag {
float: right;
margin-top: @app-menu-item-height / 2;
transform: translate(0%, -50%);
}
}
}
.basic-menu__tag {
display: inline-block;
padding: 2px 4px;
margin-right: 4px;
font-size: 12px;
line-height: 14px;
color: #fff;
border-radius: 2px;
&.dot {
width: 8px;
height: 8px;
padding: 0;
margin-top: 21px !important;
margin-bottom: 2px;
border-radius: 50%;
}
&.primary {
background: @primary-color;
}
&.error {
background: @error-color;
}
&.success {
background: @success-color;
}
&.warn {
background: @warning-color;
}
}

View File

@@ -8,14 +8,11 @@ export const basicProps = {
type: Array as PropType<Menu[]>,
default: () => [],
},
flatItems: {
type: Array as PropType<Menu[]>,
default: () => [],
},
appendClass: {
type: Boolean as PropType<boolean>,
default: false,
},
collapsedShowTitle: {
type: Boolean as PropType<boolean>,
default: false,
@@ -31,6 +28,10 @@ export const basicProps = {
type: String as PropType<MenuModeEnum>,
default: MenuModeEnum.INLINE,
},
showLogo: {
type: Boolean as PropType<boolean>,
default: false,
},
type: {
type: String as PropType<MenuTypeEnum>,
default: MenuTypeEnum.MIX,
@@ -39,10 +40,6 @@ export const basicProps = {
type: String as PropType<string>,
default: ThemeEnum.DARK,
},
showLogo: {
type: Boolean as PropType<boolean>,
default: false,
},
inlineCollapsed: {
type: Boolean as PropType<boolean>,
default: false,
@@ -57,7 +54,6 @@ export const basicProps = {
default: true,
},
beforeClickFn: {
type: Function as PropType<Fn>,
default: null,
type: Function as PropType<(key: string) => Promise<boolean>>,
},
};

View File

@@ -1,34 +1,35 @@
import { MenuModeEnum } from '/@/enums/menuEnum';
import type { Menu as MenuType } from '/@/router/types';
import type { MenuState } from './types';
import type { Ref } from 'vue';
import { computed, Ref, toRaw } from 'vue';
import { unref } from 'vue';
import { getAllParentPath } from '/@/router/helper/menuHelper';
import { es6Unique } from '/@/utils';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { getAllParentPath } from '/@/router/helper/menuHelper';
export function useOpenKeys(
menuState: MenuState,
menus: Ref<MenuType[]>,
flatMenusRef: Ref<MenuType[]>,
mode: Ref<MenuModeEnum>,
accordion: Ref<boolean>
) {
const { getCollapsed } = useMenuSetting();
function setOpenKeys(menu: MenuType) {
const flatMenus = unref(flatMenusRef);
function setOpenKeys(path: string) {
const menuList = toRaw(menus.value);
if (!unref(accordion)) {
menuState.openKeys = es6Unique([
...menuState.openKeys,
...getAllParentPath(flatMenus, menu.path),
]);
menuState.openKeys = es6Unique([...menuState.openKeys, ...getAllParentPath(menuList, path)]);
} else {
menuState.openKeys = getAllParentPath(flatMenus, menu.path);
menuState.openKeys = getAllParentPath(menuList, path);
}
}
const getOpenKeys = computed(() => {
return unref(getCollapsed) ? menuState.collapsedOpenKeys : menuState.openKeys;
});
/**
* @description: 重置值
*/
@@ -59,5 +60,5 @@ export function useOpenKeys(
}
}
}
return { setOpenKeys, resetKeys, handleOpenChange };
return { setOpenKeys, resetKeys, getOpenKeys, handleOpenChange };
}