style: lint格式化文件

This commit is contained in:
2025-10-21 18:04:02 +08:00
parent f9ca969fec
commit 7629120548
1092 changed files with 148218 additions and 157907 deletions

View File

@ -1,160 +1,142 @@
<template>
<Menu
v-bind="getBindValues"
:activeName="activeName"
:openNames="getOpenKeys"
:class="prefixCls"
:activeSubMenuNames="activeSubMenuNames"
@select="handleSelect"
>
<template v-for="item in items" :key="item.path">
<SimpleSubMenu
:item="item"
:parent="true"
:collapsedShowTitle="collapsedShowTitle"
:collapse="collapse"
/>
</template>
</Menu>
<Menu v-bind="getBindValues" :activeName="activeName" :openNames="getOpenKeys" :class="prefixCls" :activeSubMenuNames="activeSubMenuNames" @select="handleSelect">
<template v-for="item in items" :key="item.path">
<SimpleSubMenu :item="item" :parent="true" :collapsedShowTitle="collapsedShowTitle" :collapse="collapse" />
</template>
</Menu>
</template>
<script lang="ts">
import type { MenuState } from './types';
import type { Menu as MenuType } from '/@/router/types';
import type { RouteLocationNormalizedLoaded } from 'vue-router';
import { defineComponent, computed, ref, unref, reactive, toRefs, watch } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import Menu from './components/Menu.vue';
import SimpleSubMenu from './SimpleSubMenu.vue';
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
import { propTypes } from '/@/utils/propTypes';
import { REDIRECT_NAME } from '/@/router/constant';
import { useRouter } from 'vue-router';
import { isFunction, isUrl } from '/@/utils/is';
import { openWindow } from '/@/utils';
import type { MenuState } from './types';
import type { Menu as MenuType } from '/@/router/types';
import type { RouteLocationNormalizedLoaded } from 'vue-router';
import { defineComponent, computed, ref, unref, reactive, toRefs, watch } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import Menu from './components/Menu.vue';
import SimpleSubMenu from './SimpleSubMenu.vue';
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
import { propTypes } from '/@/utils/propTypes';
import { REDIRECT_NAME } from '/@/router/constant';
import { useRouter } from 'vue-router';
import { isFunction, isUrl } from '/@/utils/is';
import { openWindow } from '/@/utils';
import { useOpenKeys } from './useOpenKeys';
export default defineComponent({
name: 'SimpleMenu',
components: {
Menu,
SimpleSubMenu,
},
inheritAttrs: false,
props: {
items: {
type: Array as PropType<MenuType[]>,
default: () => [],
},
collapse: propTypes.bool,
mixSider: propTypes.bool,
theme: propTypes.string,
accordion: propTypes.bool.def(true),
collapsedShowTitle: propTypes.bool,
beforeClickFn: {
type: Function as PropType<(key: string) => Promise<boolean>>,
},
isSplitMenu: propTypes.bool,
},
emits: ['menuClick'],
setup(props, { attrs, emit }) {
const currentActiveMenu = ref('');
const isClickGo = ref(false);
const menuState = reactive<MenuState>({
activeName: '',
openNames: [],
activeSubMenuNames: [],
});
const { currentRoute } = useRouter();
const { prefixCls } = useDesign('simple-menu');
const { items, accordion, mixSider, collapse } = toRefs(props);
const { setOpenKeys, getOpenKeys } = useOpenKeys(
menuState,
items,
accordion,
mixSider,
collapse,
);
const getBindValues = computed(() => ({ ...attrs, ...props }));
watch(
() => props.collapse,
(collapse) => {
if (collapse) {
menuState.openNames = [];
} else {
setOpenKeys(currentRoute.value.path);
}
import { useOpenKeys } from './useOpenKeys';
export default defineComponent({
name: 'SimpleMenu',
components: {
Menu,
SimpleSubMenu
},
{ immediate: true },
);
watch(
() => props.items,
() => {
if (!props.isSplitMenu) {
return;
}
setOpenKeys(currentRoute.value.path);
inheritAttrs: false,
props: {
items: {
type: Array as PropType<MenuType[]>,
default: () => []
},
collapse: propTypes.bool,
mixSider: propTypes.bool,
theme: propTypes.string,
accordion: propTypes.bool.def(true),
collapsedShowTitle: propTypes.bool,
beforeClickFn: {
type: Function as PropType<(key: string) => Promise<boolean>>
},
isSplitMenu: propTypes.bool
},
{ flush: 'post' },
);
emits: ['menuClick'],
setup(props, { attrs, emit }) {
const currentActiveMenu = ref('');
const isClickGo = ref(false);
listenerRouteChange((route) => {
if (route.name === REDIRECT_NAME) return;
const menuState = reactive<MenuState>({
activeName: '',
openNames: [],
activeSubMenuNames: []
});
currentActiveMenu.value = route.meta?.currentActiveMenu as string;
handleMenuChange(route);
const { currentRoute } = useRouter();
const { prefixCls } = useDesign('simple-menu');
const { items, accordion, mixSider, collapse } = toRefs(props);
if (unref(currentActiveMenu)) {
menuState.activeName = unref(currentActiveMenu);
setOpenKeys(unref(currentActiveMenu));
const { setOpenKeys, getOpenKeys } = useOpenKeys(menuState, items, accordion, mixSider, collapse);
const getBindValues = computed(() => ({ ...attrs, ...props }));
watch(
() => props.collapse,
(collapse) => {
if (collapse) {
menuState.openNames = [];
} else {
setOpenKeys(currentRoute.value.path);
}
},
{ immediate: true }
);
watch(
() => props.items,
() => {
if (!props.isSplitMenu) {
return;
}
setOpenKeys(currentRoute.value.path);
},
{ flush: 'post' }
);
listenerRouteChange((route) => {
if (route.name === REDIRECT_NAME) return;
currentActiveMenu.value = route.meta?.currentActiveMenu as string;
handleMenuChange(route);
if (unref(currentActiveMenu)) {
menuState.activeName = unref(currentActiveMenu);
setOpenKeys(unref(currentActiveMenu));
}
});
async function handleMenuChange(route?: RouteLocationNormalizedLoaded) {
if (unref(isClickGo)) {
isClickGo.value = false;
return;
}
const path = (route || unref(currentRoute)).path;
menuState.activeName = path;
setOpenKeys(path);
}
async function handleSelect(key: string) {
if (isUrl(key)) {
openWindow(key);
return;
}
const { beforeClickFn } = props;
if (beforeClickFn && isFunction(beforeClickFn)) {
const flag = await beforeClickFn(key);
if (!flag) return;
}
emit('menuClick', key);
isClickGo.value = true;
setOpenKeys(key);
menuState.activeName = key;
}
return {
prefixCls,
getBindValues,
handleSelect,
getOpenKeys,
...toRefs(menuState)
};
}
});
async function handleMenuChange(route?: RouteLocationNormalizedLoaded) {
if (unref(isClickGo)) {
isClickGo.value = false;
return;
}
const path = (route || unref(currentRoute)).path;
menuState.activeName = path;
setOpenKeys(path);
}
async function handleSelect(key: string) {
if (isUrl(key)) {
openWindow(key);
return;
}
const { beforeClickFn } = props;
if (beforeClickFn && isFunction(beforeClickFn)) {
const flag = await beforeClickFn(key);
if (!flag) return;
}
emit('menuClick', key);
isClickGo.value = true;
setOpenKeys(key);
menuState.activeName = key;
}
return {
prefixCls,
getBindValues,
handleSelect,
getOpenKeys,
...toRefs(menuState),
};
},
});
});
</script>
<style lang="less">
@import './index.less';
@import './index.less';
</style>

View File

@ -1,68 +1,68 @@
<template>
<span :class="getTagClass" v-if="getShowTag">{{ getContent }}</span>
<span :class="getTagClass" v-if="getShowTag">{{ getContent }}</span>
</template>
<script lang="ts">
import type { Menu } from '/@/router/types';
import type { Menu } from '/@/router/types';
import { defineComponent, computed } from 'vue';
import { defineComponent, computed } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
export default defineComponent({
name: 'SimpleMenuTag',
props: {
item: {
type: Object as PropType<Menu>,
default: () => ({}),
},
dot: propTypes.bool,
collapseParent: propTypes.bool,
},
setup(props) {
const { prefixCls } = useDesign('simple-menu');
export default defineComponent({
name: 'SimpleMenuTag',
props: {
item: {
type: Object as PropType<Menu>,
default: () => ({})
},
dot: propTypes.bool,
collapseParent: propTypes.bool
},
setup(props) {
const { prefixCls } = useDesign('simple-menu');
const getShowTag = computed(() => {
const { item } = props;
const getShowTag = computed(() => {
const { item } = props;
if (!item) return false;
if (!item) return false;
const { tag } = item;
if (!tag) return false;
const { tag } = item;
if (!tag) return false;
const { dot, content } = tag;
if (!dot && !content) return false;
return true;
});
const { dot, content } = tag;
if (!dot && !content) return false;
return true;
});
const getContent = computed(() => {
if (!getShowTag.value) return '';
const { item, collapseParent } = props;
const { tag } = item;
const { dot, content } = tag!;
return dot || collapseParent ? '' : content;
});
const getContent = computed(() => {
if (!getShowTag.value) return '';
const { item, collapseParent } = props;
const { tag } = item;
const { dot, content } = tag!;
return dot || collapseParent ? '' : content;
});
const getTagClass = computed(() => {
const { item, collapseParent } = props;
const { tag = {} } = item || {};
const { dot, type = 'error' } = tag;
const tagCls = `${prefixCls}-tag`;
return [
tagCls,
const getTagClass = computed(() => {
const { item, collapseParent } = props;
const { tag = {} } = item || {};
const { dot, type = 'error' } = tag;
const tagCls = `${prefixCls}-tag`;
return [
tagCls,
[`${tagCls}--${type}`],
{
[`${tagCls}--collapse`]: collapseParent,
[`${tagCls}--dot`]: dot || props.dot,
},
];
});
return {
getTagClass,
getShowTag,
getContent,
};
},
});
[`${tagCls}--${type}`],
{
[`${tagCls}--collapse`]: collapseParent,
[`${tagCls}--dot`]: dot || props.dot
}
];
});
return {
getTagClass,
getShowTag,
getContent
};
}
});
</script>

View File

@ -1,114 +1,98 @@
<template>
<MenuItem
:name="item.path"
v-if="!menuHasChildren(item) && getShowMenu"
v-bind="$props"
:class="getLevelClass"
>
<Icon v-if="getIcon" :icon="getIcon" :size="16" />
<div v-if="collapsedShowTitle && getIsCollapseParent" class="mt-1 collapse-title">
{{ getI18nName }}
</div>
<template #title>
<span :class="['ml-2', `${prefixCls}-sub-title`]">
{{ getI18nName }}
</span>
<SimpleMenuTag :item="item" :collapseParent="getIsCollapseParent" />
</template>
</MenuItem>
<SubMenu
:name="item.path"
v-if="menuHasChildren(item) && getShowMenu"
:class="[getLevelClass, theme]"
:collapsedShowTitle="collapsedShowTitle"
>
<template #title>
<Icon v-if="getIcon" :icon="getIcon" :size="16" />
<MenuItem :name="item.path" v-if="!menuHasChildren(item) && getShowMenu" v-bind="$props" :class="getLevelClass">
<Icon v-if="getIcon" :icon="getIcon" :size="16" />
<div v-if="collapsedShowTitle && getIsCollapseParent" class="mt-1 collapse-title">
{{ getI18nName }}
</div>
<template #title>
<span :class="['ml-2', `${prefixCls}-sub-title`]">
{{ getI18nName }}
</span>
<SimpleMenuTag :item="item" :collapseParent="getIsCollapseParent" />
</template>
</MenuItem>
<SubMenu :name="item.path" v-if="menuHasChildren(item) && getShowMenu" :class="[getLevelClass, theme]" :collapsedShowTitle="collapsedShowTitle">
<template #title>
<Icon v-if="getIcon" :icon="getIcon" :size="16" />
<div v-if="collapsedShowTitle && getIsCollapseParent" class="mt-2 collapse-title">
{{ getI18nName }}
</div>
<div v-if="collapsedShowTitle && getIsCollapseParent" class="mt-2 collapse-title">
{{ getI18nName }}
</div>
<span v-show="getShowSubTitle" :class="['ml-2', `${prefixCls}-sub-title`]">
{{ getI18nName }}
</span>
<SimpleMenuTag :item="item" :collapseParent="!!collapse && !!parent" />
</template>
<template v-for="childrenItem in item.children || []" :key="childrenItem.path">
<SimpleSubMenu v-bind="$props" :item="childrenItem" :parent="false" />
</template>
</SubMenu>
<span v-show="getShowSubTitle" :class="['ml-2', `${prefixCls}-sub-title`]">
{{ getI18nName }}
</span>
<SimpleMenuTag :item="item" :collapseParent="!!collapse && !!parent" />
</template>
<template v-for="childrenItem in item.children || []" :key="childrenItem.path">
<SimpleSubMenu v-bind="$props" :item="childrenItem" :parent="false" />
</template>
</SubMenu>
</template>
<script lang="ts">
import type { PropType } from 'vue';
import type { Menu } from '/@/router/types';
import type { PropType } from 'vue';
import type { Menu } from '/@/router/types';
import { defineComponent, computed } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import Icon from '/@/components/Icon/index';
import { defineComponent, computed } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import Icon from '/@/components/Icon/index';
import MenuItem from './components/MenuItem.vue';
import SubMenu from './components/SubMenuItem.vue';
import { propTypes } from '/@/utils/propTypes';
import { useI18n } from '/@/hooks/web/useI18n';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
import MenuItem from './components/MenuItem.vue';
import SubMenu from './components/SubMenuItem.vue';
import { propTypes } from '/@/utils/propTypes';
import { useI18n } from '/@/hooks/web/useI18n';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
export default defineComponent({
name: 'SimpleSubMenu',
components: {
SubMenu,
MenuItem,
SimpleMenuTag: createAsyncComponent(() => import('./SimpleMenuTag.vue')),
Icon,
},
props: {
item: {
type: Object as PropType<Menu>,
default: () => ({}),
},
parent: propTypes.bool,
collapsedShowTitle: propTypes.bool,
collapse: propTypes.bool,
theme: propTypes.oneOf(['dark', 'light']),
},
setup(props) {
const { t } = useI18n();
const { prefixCls } = useDesign('simple-menu');
export default defineComponent({
name: 'SimpleSubMenu',
components: {
SubMenu,
MenuItem,
SimpleMenuTag: createAsyncComponent(() => import('./SimpleMenuTag.vue')),
Icon
},
props: {
item: {
type: Object as PropType<Menu>,
default: () => ({})
},
parent: propTypes.bool,
collapsedShowTitle: propTypes.bool,
collapse: propTypes.bool,
theme: propTypes.oneOf(['dark', 'light'])
},
setup(props) {
const { t } = useI18n();
const { prefixCls } = useDesign('simple-menu');
const getShowMenu = computed(() => !props.item?.meta?.hideMenu);
const getIcon = computed(() => props.item?.icon || 'ant-design:menu-outlined');
const getI18nName = computed(() => t(props.item?.name));
const getShowSubTitle = computed(() => !props.collapse || !props.parent);
const getIsCollapseParent = computed(() => !!props.collapse && !!props.parent);
const getLevelClass = computed(() => {
return [
{
[`${prefixCls}__parent`]: props.parent,
[`${prefixCls}__children`]: !props.parent,
},
];
});
const getShowMenu = computed(() => !props.item?.meta?.hideMenu);
const getIcon = computed(() => props.item?.icon || 'ant-design:menu-outlined');
const getI18nName = computed(() => t(props.item?.name));
const getShowSubTitle = computed(() => !props.collapse || !props.parent);
const getIsCollapseParent = computed(() => !!props.collapse && !!props.parent);
const getLevelClass = computed(() => {
return [
{
[`${prefixCls}__parent`]: props.parent,
[`${prefixCls}__children`]: !props.parent
}
];
});
function menuHasChildren(menuTreeItem: Menu): boolean {
return (
(!menuTreeItem.meta?.hideChildrenInMenu &&
Reflect.has(menuTreeItem, 'children') &&
!!menuTreeItem.children &&
menuTreeItem.children.length > 0) ||
menuTreeItem.meta?.menuType === 0
);
}
function menuHasChildren(menuTreeItem: Menu): boolean {
return (!menuTreeItem.meta?.hideChildrenInMenu && Reflect.has(menuTreeItem, 'children') && !!menuTreeItem.children && menuTreeItem.children.length > 0) || menuTreeItem.meta?.menuType === 0;
}
return {
prefixCls,
menuHasChildren,
getShowMenu,
getIcon,
getI18nName,
getShowSubTitle,
getLevelClass,
getIsCollapseParent,
};
},
});
return {
prefixCls,
menuHasChildren,
getShowMenu,
getIcon,
getI18nName,
getShowSubTitle,
getLevelClass,
getIsCollapseParent
};
}
});
</script>

View File

@ -1,158 +1,148 @@
<template>
<ul :class="getClass">
<slot></slot>
</ul>
<ul :class="getClass">
<slot></slot>
</ul>
</template>
<script lang="ts">
import type { PropType } from 'vue';
import type { SubMenuProvider } from './types';
import {
defineComponent,
ref,
computed,
onMounted,
watchEffect,
watch,
nextTick,
getCurrentInstance,
provide,
} from 'vue';
import type { PropType } from 'vue';
import type { SubMenuProvider } from './types';
import { defineComponent, ref, computed, onMounted, watchEffect, watch, nextTick, getCurrentInstance, provide } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
import { createSimpleRootMenuContext } from './useSimpleMenuContext';
import mitt from '/@/utils/mitt';
export default defineComponent({
name: 'Menu',
props: {
theme: propTypes.oneOf(['light', 'dark']).def('light'),
activeName: propTypes.oneOfType([propTypes.string, propTypes.number]),
openNames: {
type: Array as PropType<string[]>,
default: () => [],
},
accordion: propTypes.bool.def(true),
width: propTypes.string.def('100%'),
collapsedWidth: propTypes.string.def('48px'),
indentSize: propTypes.number.def(16),
collapse: propTypes.bool.def(true),
activeSubMenuNames: {
type: Array as PropType<(string | number)[]>,
default: () => [],
},
},
emits: ['select', 'open-change'],
setup(props, { emit }) {
const rootMenuEmitter = mitt();
const instance = getCurrentInstance();
const currentActiveName = ref<string | number>('');
const openedNames = ref<string[]>([]);
const { prefixCls } = useDesign('menu');
const isRemoveAllPopup = ref(false);
createSimpleRootMenuContext({
rootMenuEmitter: rootMenuEmitter,
activeName: currentActiveName,
});
const getClass = computed(() => {
const { theme } = props;
return [
prefixCls,
`${prefixCls}-${theme}`,
`${prefixCls}-vertical`,
{
[`${prefixCls}-collapse`]: props.collapse,
},
];
});
watchEffect(() => {
openedNames.value = props.openNames;
});
watchEffect(() => {
if (props.activeName) {
currentActiveName.value = props.activeName;
}
});
watch(
() => props.openNames,
() => {
nextTick(() => {
updateOpened();
});
import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
import { createSimpleRootMenuContext } from './useSimpleMenuContext';
import mitt from '/@/utils/mitt';
export default defineComponent({
name: 'Menu',
props: {
theme: propTypes.oneOf(['light', 'dark']).def('light'),
activeName: propTypes.oneOfType([propTypes.string, propTypes.number]),
openNames: {
type: Array as PropType<string[]>,
default: () => []
},
accordion: propTypes.bool.def(true),
width: propTypes.string.def('100%'),
collapsedWidth: propTypes.string.def('48px'),
indentSize: propTypes.number.def(16),
collapse: propTypes.bool.def(true),
activeSubMenuNames: {
type: Array as PropType<(string | number)[]>,
default: () => []
}
},
);
emits: ['select', 'open-change'],
setup(props, { emit }) {
const rootMenuEmitter = mitt();
const instance = getCurrentInstance();
function updateOpened() {
rootMenuEmitter.emit('on-update-opened', openedNames.value);
}
const currentActiveName = ref<string | number>('');
const openedNames = ref<string[]>([]);
function addSubMenu(name: string) {
if (openedNames.value.includes(name)) return;
openedNames.value.push(name);
updateOpened();
}
const { prefixCls } = useDesign('menu');
function removeSubMenu(name: string) {
openedNames.value = openedNames.value.filter((item) => item !== name);
updateOpened();
}
const isRemoveAllPopup = ref(false);
function removeAll() {
openedNames.value = [];
updateOpened();
}
createSimpleRootMenuContext({
rootMenuEmitter: rootMenuEmitter,
activeName: currentActiveName
});
function sliceIndex(index: number) {
if (index === -1) return;
openedNames.value = openedNames.value.slice(0, index + 1);
updateOpened();
}
const getClass = computed(() => {
const { theme } = props;
return [
prefixCls,
`${prefixCls}-${theme}`,
`${prefixCls}-vertical`,
{
[`${prefixCls}-collapse`]: props.collapse
}
];
});
provide<SubMenuProvider>(`subMenu:${instance?.uid}`, {
addSubMenu,
removeSubMenu,
getOpenNames: () => openedNames.value,
removeAll,
isRemoveAllPopup,
sliceIndex,
level: 0,
props: props as any,
});
watchEffect(() => {
openedNames.value = props.openNames;
});
onMounted(() => {
openedNames.value = !props.collapse ? [...props.openNames] : [];
updateOpened();
rootMenuEmitter.on('on-menu-item-select', (name: string) => {
currentActiveName.value = name;
watchEffect(() => {
if (props.activeName) {
currentActiveName.value = props.activeName;
}
});
nextTick(() => {
props.collapse && removeAll();
});
emit('select', name);
});
watch(
() => props.openNames,
() => {
nextTick(() => {
updateOpened();
});
}
);
rootMenuEmitter.on('open-name-change', ({ name, opened }) => {
if (opened && !openedNames.value.includes(name)) {
openedNames.value.push(name);
} else if (!opened) {
const index = openedNames.value.findIndex((item) => item === name);
index !== -1 && openedNames.value.splice(index, 1);
}
});
});
function updateOpened() {
rootMenuEmitter.emit('on-update-opened', openedNames.value);
}
return { getClass, openedNames };
},
});
function addSubMenu(name: string) {
if (openedNames.value.includes(name)) return;
openedNames.value.push(name);
updateOpened();
}
function removeSubMenu(name: string) {
openedNames.value = openedNames.value.filter((item) => item !== name);
updateOpened();
}
function removeAll() {
openedNames.value = [];
updateOpened();
}
function sliceIndex(index: number) {
if (index === -1) return;
openedNames.value = openedNames.value.slice(0, index + 1);
updateOpened();
}
provide<SubMenuProvider>(`subMenu:${instance?.uid}`, {
addSubMenu,
removeSubMenu,
getOpenNames: () => openedNames.value,
removeAll,
isRemoveAllPopup,
sliceIndex,
level: 0,
props: props as any
});
onMounted(() => {
openedNames.value = !props.collapse ? [...props.openNames] : [];
updateOpened();
rootMenuEmitter.on('on-menu-item-select', (name: string) => {
currentActiveName.value = name;
nextTick(() => {
props.collapse && removeAll();
});
emit('select', name);
});
rootMenuEmitter.on('open-name-change', ({ name, opened }) => {
if (opened && !openedNames.value.includes(name)) {
openedNames.value.push(name);
} else if (!opened) {
const index = openedNames.value.findIndex((item) => item === name);
index !== -1 && openedNames.value.splice(index, 1);
}
});
});
return { getClass, openedNames };
}
});
</script>
<style lang="less">
@import './menu.less';
@import './menu.less';
</style>

View File

@ -1,78 +1,78 @@
<template>
<transition mode="out-in" v-on="on">
<slot></slot>
</transition>
<transition mode="out-in" v-on="on">
<slot></slot>
</transition>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { addClass, removeClass } from '/@/utils/domUtils';
import { defineComponent } from 'vue';
import { addClass, removeClass } from '/@/utils/domUtils';
export default defineComponent({
name: 'MenuCollapseTransition',
setup() {
return {
on: {
beforeEnter(el) {
addClass(el, 'collapse-transition');
if (!el.dataset) el.dataset = {};
export default defineComponent({
name: 'MenuCollapseTransition',
setup() {
return {
on: {
beforeEnter(el) {
addClass(el, 'collapse-transition');
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.style.height = '0';
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
},
el.style.height = '0';
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
},
enter(el) {
el.dataset.oldOverflow = el.style.overflow;
if (el.scrollHeight !== 0) {
el.style.height = el.scrollHeight + 'px';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
} else {
el.style.height = '';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
enter(el) {
el.dataset.oldOverflow = el.style.overflow;
if (el.scrollHeight !== 0) {
el.style.height = el.scrollHeight + 'px';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
} else {
el.style.height = '';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
el.style.overflow = 'hidden';
},
el.style.overflow = 'hidden';
},
afterEnter(el) {
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
},
afterEnter(el) {
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
},
beforeLeave(el) {
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldOverflow = el.style.overflow;
beforeLeave(el) {
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldOverflow = el.style.overflow;
el.style.height = el.scrollHeight + 'px';
el.style.overflow = 'hidden';
},
el.style.height = el.scrollHeight + 'px';
el.style.overflow = 'hidden';
},
leave(el) {
if (el.scrollHeight !== 0) {
addClass(el, 'collapse-transition');
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
},
leave(el) {
if (el.scrollHeight !== 0) {
addClass(el, 'collapse-transition');
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
},
afterLeave(el) {
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
},
},
};
},
});
afterLeave(el) {
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
}
};
}
});
</script>

View File

@ -1,107 +1,106 @@
<template>
<li :class="getClass" @click.stop="handleClickItem" :style="getCollapse ? {} : getItemStyle">
<Tooltip placement="right" v-if="showTooptip">
<template #title>
<slot name="title"></slot>
</template>
<div :class="`${prefixCls}-tooltip`">
<slot></slot>
</div>
</Tooltip>
<li :class="getClass" @click.stop="handleClickItem" :style="getCollapse ? {} : getItemStyle">
<Tooltip placement="right" v-if="showTooptip">
<template #title>
<slot name="title"></slot>
</template>
<div :class="`${prefixCls}-tooltip`">
<slot></slot>
</div>
</Tooltip>
<template v-else>
<slot></slot>
<slot name="title"></slot>
</template>
</li>
<template v-else>
<slot></slot>
<slot name="title"></slot>
</template>
</li>
</template>
<script lang="ts">
import { PropType } from 'vue';
import { defineComponent, ref, computed, unref, getCurrentInstance, watch } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
import { useMenuItem } from './useMenu';
import { Tooltip } from 'ant-design-vue';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
export default defineComponent({
name: 'MenuItem',
components: { Tooltip },
props: {
name: {
type: [String, Number] as PropType<string | number>,
required: true,
},
disabled: propTypes.bool,
},
setup(props, { slots }) {
const instance = getCurrentInstance();
import { PropType } from 'vue';
import { defineComponent, ref, computed, unref, getCurrentInstance, watch } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
import { useMenuItem } from './useMenu';
import { Tooltip } from 'ant-design-vue';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
export default defineComponent({
name: 'MenuItem',
components: { Tooltip },
props: {
name: {
type: [String, Number] as PropType<string | number>,
required: true
},
disabled: propTypes.bool
},
setup(props, { slots }) {
const instance = getCurrentInstance();
const active = ref(false);
const active = ref(false);
const { getItemStyle, getParentList, getParentMenu, getParentRootMenu } =
useMenuItem(instance);
const { getItemStyle, getParentList, getParentMenu, getParentRootMenu } = useMenuItem(instance);
const { prefixCls } = useDesign('menu');
const { prefixCls } = useDesign('menu');
const { rootMenuEmitter, activeName } = useSimpleRootMenuContext();
const { rootMenuEmitter, activeName } = useSimpleRootMenuContext();
const getClass = computed(() => {
return [
`${prefixCls}-item`,
{
[`${prefixCls}-item-active`]: unref(active),
[`${prefixCls}-item-selected`]: unref(active),
[`${prefixCls}-item-disabled`]: !!props.disabled,
},
];
});
const getCollapse = computed(() => unref(getParentRootMenu)?.props.collapse);
const showTooptip = computed(() => {
return unref(getParentMenu)?.type.name === 'Menu' && unref(getCollapse) && slots.title;
});
function handleClickItem() {
const { disabled } = props;
if (disabled) {
return;
}
rootMenuEmitter.emit('on-menu-item-select', props.name);
if (unref(getCollapse)) {
return;
}
const { uidList } = getParentList();
rootMenuEmitter.emit('on-update-opened', {
opend: false,
parent: instance?.parent,
uidList: uidList,
});
}
watch(
() => activeName.value,
(name: string) => {
if (name === props.name) {
const { list, uidList } = getParentList();
active.value = true;
list.forEach((item) => {
if (item.proxy) {
(item.proxy as any).active = true;
}
const getClass = computed(() => {
return [
`${prefixCls}-item`,
{
[`${prefixCls}-item-active`]: unref(active),
[`${prefixCls}-item-selected`]: unref(active),
[`${prefixCls}-item-disabled`]: !!props.disabled
}
];
});
rootMenuEmitter.emit('on-update-active-name:submenu', uidList);
} else {
active.value = false;
}
},
{ immediate: true },
);
const getCollapse = computed(() => unref(getParentRootMenu)?.props.collapse);
return { getClass, prefixCls, getItemStyle, getCollapse, handleClickItem, showTooptip };
},
});
const showTooptip = computed(() => {
return unref(getParentMenu)?.type.name === 'Menu' && unref(getCollapse) && slots.title;
});
function handleClickItem() {
const { disabled } = props;
if (disabled) {
return;
}
rootMenuEmitter.emit('on-menu-item-select', props.name);
if (unref(getCollapse)) {
return;
}
const { uidList } = getParentList();
rootMenuEmitter.emit('on-update-opened', {
opend: false,
parent: instance?.parent,
uidList: uidList
});
}
watch(
() => activeName.value,
(name: string) => {
if (name === props.name) {
const { list, uidList } = getParentList();
active.value = true;
list.forEach((item) => {
if (item.proxy) {
(item.proxy as any).active = true;
}
});
rootMenuEmitter.emit('on-update-active-name:submenu', uidList);
} else {
active.value = false;
}
},
{ immediate: true }
);
return { getClass, prefixCls, getItemStyle, getCollapse, handleClickItem, showTooptip };
}
});
</script>

View File

@ -1,334 +1,303 @@
<template>
<li :class="getClass">
<template v-if="!getCollapse">
<div :class="`${prefixCls}-submenu-title`" @click.stop="handleClick" :style="getItemStyle">
<slot name="title"></slot>
<Icon
icon="eva:arrow-ios-downward-outline"
:size="14"
:class="`${prefixCls}-submenu-title-icon`"
/>
</div>
<CollapseTransition>
<ul :class="prefixCls" v-show="opened">
<slot></slot>
</ul>
</CollapseTransition>
</template>
<li :class="getClass">
<template v-if="!getCollapse">
<div :class="`${prefixCls}-submenu-title`" @click.stop="handleClick" :style="getItemStyle">
<slot name="title"></slot>
<Icon icon="eva:arrow-ios-downward-outline" :size="14" :class="`${prefixCls}-submenu-title-icon`" />
</div>
<CollapseTransition>
<ul :class="prefixCls" v-show="opened">
<slot></slot>
</ul>
</CollapseTransition>
</template>
<Popover
placement="right"
:overlayClassName="`${prefixCls}-menu-popover`"
v-else
:visible="getIsOpend"
@visible-change="handleVisibleChange"
:overlayStyle="getOverlayStyle"
:align="{ offset: [0, 0] }"
>
<div :class="getSubClass" v-bind="getEvents(false)">
<div
:class="[
{
[`${prefixCls}-submenu-popup`]: !getParentSubMenu,
[`${prefixCls}-submenu-collapsed-show-tit`]: collapsedShowTitle,
},
]"
>
<slot name="title"></slot>
</div>
<Icon
v-if="getParentSubMenu"
icon="eva:arrow-ios-downward-outline"
:size="14"
:class="`${prefixCls}-submenu-title-icon`"
/>
</div>
<!-- eslint-disable-next-line -->
<template #content v-show="opened">
<div v-bind="getEvents(true)">
<ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]">
<slot></slot>
</ul>
</div>
</template>
</Popover>
</li>
<Popover placement="right" :overlayClassName="`${prefixCls}-menu-popover`" v-else :visible="getIsOpend" @visible-change="handleVisibleChange" :overlayStyle="getOverlayStyle" :align="{ offset: [0, 0] }">
<div :class="getSubClass" v-bind="getEvents(false)">
<div
:class="[
{
[`${prefixCls}-submenu-popup`]: !getParentSubMenu,
[`${prefixCls}-submenu-collapsed-show-tit`]: collapsedShowTitle
}
]"
>
<slot name="title"></slot>
</div>
<Icon v-if="getParentSubMenu" icon="eva:arrow-ios-downward-outline" :size="14" :class="`${prefixCls}-submenu-title-icon`" />
</div>
<!-- eslint-disable-next-line -->
<template #content v-show="opened">
<div v-bind="getEvents(true)">
<ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]">
<slot></slot>
</ul>
</div>
</template>
</Popover>
</li>
</template>
<script lang="ts">
import type { CSSProperties, PropType } from 'vue';
import type { SubMenuProvider } from './types';
import {
defineComponent,
computed,
unref,
getCurrentInstance,
toRefs,
reactive,
provide,
onBeforeMount,
inject,
} from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
import { useMenuItem } from './useMenu';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
import { CollapseTransition } from '/@/components/Transition';
import Icon from '/@/components/Icon';
import { Popover } from 'ant-design-vue';
import { isBoolean, isObject } from '/@/utils/is';
import mitt from '/@/utils/mitt';
import type { CSSProperties, PropType } from 'vue';
import type { SubMenuProvider } from './types';
import { defineComponent, computed, unref, getCurrentInstance, toRefs, reactive, provide, onBeforeMount, inject } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
import { useMenuItem } from './useMenu';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
import { CollapseTransition } from '/@/components/Transition';
import Icon from '/@/components/Icon';
import { Popover } from 'ant-design-vue';
import { isBoolean, isObject } from '/@/utils/is';
import mitt from '/@/utils/mitt';
const DELAY = 200;
export default defineComponent({
name: 'SubMenu',
components: {
Icon,
CollapseTransition,
Popover,
},
props: {
name: {
type: [String, Number] as PropType<string | number>,
required: true,
},
disabled: propTypes.bool,
collapsedShowTitle: propTypes.bool,
},
setup(props) {
const instance = getCurrentInstance();
const DELAY = 200;
export default defineComponent({
name: 'SubMenu',
components: {
Icon,
CollapseTransition,
Popover
},
props: {
name: {
type: [String, Number] as PropType<string | number>,
required: true
},
disabled: propTypes.bool,
collapsedShowTitle: propTypes.bool
},
setup(props) {
const instance = getCurrentInstance();
const state = reactive({
active: false,
opened: false,
});
const state = reactive({
active: false,
opened: false
});
const data = reactive({
timeout: null as TimeoutHandle | null,
mouseInChild: false,
isChild: false,
});
const data = reactive({
timeout: null as TimeoutHandle | null,
mouseInChild: false,
isChild: false
});
const { getParentSubMenu, getItemStyle, getParentMenu, getParentList } =
useMenuItem(instance);
const { getParentSubMenu, getItemStyle, getParentMenu, getParentList } = useMenuItem(instance);
const { prefixCls } = useDesign('menu');
const { prefixCls } = useDesign('menu');
const subMenuEmitter = mitt();
const subMenuEmitter = mitt();
const { rootMenuEmitter } = useSimpleRootMenuContext();
const { rootMenuEmitter } = useSimpleRootMenuContext();
const {
addSubMenu: parentAddSubmenu,
removeSubMenu: parentRemoveSubmenu,
removeAll: parentRemoveAll,
getOpenNames: parentGetOpenNames,
isRemoveAllPopup,
sliceIndex,
level,
props: rootProps,
handleMouseleave: parentHandleMouseleave,
} = inject<SubMenuProvider>(`subMenu:${getParentMenu.value?.uid}`)!;
const {
addSubMenu: parentAddSubmenu,
removeSubMenu: parentRemoveSubmenu,
removeAll: parentRemoveAll,
getOpenNames: parentGetOpenNames,
isRemoveAllPopup,
sliceIndex,
level,
props: rootProps,
handleMouseleave: parentHandleMouseleave
} = inject<SubMenuProvider>(`subMenu:${getParentMenu.value?.uid}`)!;
const getClass = computed(() => {
return [
`${prefixCls}-submenu`,
{
[`${prefixCls}-item-active`]: state.active,
[`${prefixCls}-opened`]: state.opened,
[`${prefixCls}-submenu-disabled`]: props.disabled,
[`${prefixCls}-submenu-has-parent-submenu`]: unref(getParentSubMenu),
[`${prefixCls}-child-item-active`]: state.active,
},
];
});
const getClass = computed(() => {
return [
`${prefixCls}-submenu`,
{
[`${prefixCls}-item-active`]: state.active,
[`${prefixCls}-opened`]: state.opened,
[`${prefixCls}-submenu-disabled`]: props.disabled,
[`${prefixCls}-submenu-has-parent-submenu`]: unref(getParentSubMenu),
[`${prefixCls}-child-item-active`]: state.active
}
];
});
const getAccordion = computed(() => rootProps.accordion);
const getCollapse = computed(() => rootProps.collapse);
const getTheme = computed(() => rootProps.theme);
const getAccordion = computed(() => rootProps.accordion);
const getCollapse = computed(() => rootProps.collapse);
const getTheme = computed(() => rootProps.theme);
const getOverlayStyle = computed((): CSSProperties => {
return {
minWidth: '200px',
};
});
const getOverlayStyle = computed((): CSSProperties => {
return {
minWidth: '200px'
};
});
const getIsOpend = computed(() => {
const name = props.name;
if (unref(getCollapse)) {
return parentGetOpenNames().includes(name);
}
return state.opened;
});
const getIsOpend = computed(() => {
const name = props.name;
if (unref(getCollapse)) {
return parentGetOpenNames().includes(name);
}
return state.opened;
});
const getSubClass = computed(() => {
const isActive = rootProps.activeSubMenuNames.includes(props.name);
return [
`${prefixCls}-submenu-title`,
{
[`${prefixCls}-submenu-active`]: isActive,
[`${prefixCls}-submenu-active-border`]: isActive && level === 0,
[`${prefixCls}-submenu-collapse`]: unref(getCollapse) && level === 0,
},
];
});
const getSubClass = computed(() => {
const isActive = rootProps.activeSubMenuNames.includes(props.name);
return [
`${prefixCls}-submenu-title`,
{
[`${prefixCls}-submenu-active`]: isActive,
[`${prefixCls}-submenu-active-border`]: isActive && level === 0,
[`${prefixCls}-submenu-collapse`]: unref(getCollapse) && level === 0
}
];
});
function getEvents(deep: boolean) {
if (!unref(getCollapse)) {
return {};
}
return {
onMouseenter: handleMouseenter,
onMouseleave: () => handleMouseleave(deep),
};
}
function handleClick() {
const { disabled } = props;
if (disabled || unref(getCollapse)) return;
const opened = state.opened;
if (unref(getAccordion)) {
const { uidList } = getParentList();
rootMenuEmitter.emit('on-update-opened', {
opend: false,
parent: instance?.parent,
uidList: uidList,
});
} else {
rootMenuEmitter.emit('open-name-change', {
name: props.name,
opened: !opened,
});
}
state.opened = !opened;
}
function handleMouseenter() {
const disabled = props.disabled;
if (disabled) return;
subMenuEmitter.emit('submenu:mouse-enter-child');
const index = parentGetOpenNames().findIndex((item) => item === props.name);
sliceIndex(index);
const isRoot = level === 0 && parentGetOpenNames().length === 2;
if (isRoot) {
parentRemoveAll();
}
data.isChild = parentGetOpenNames().includes(props.name);
clearTimeout(data.timeout!);
data.timeout = setTimeout(() => {
parentAddSubmenu(props.name);
}, DELAY);
}
function handleMouseleave(deepDispatch = false) {
const parentName = getParentMenu.value?.props.name;
if (!parentName) {
isRemoveAllPopup.value = true;
}
if (parentGetOpenNames().slice(-1)[0] === props.name) {
data.isChild = false;
}
subMenuEmitter.emit('submenu:mouse-leave-child');
if (data.timeout) {
clearTimeout(data.timeout!);
data.timeout = setTimeout(() => {
if (isRemoveAllPopup.value) {
parentRemoveAll();
} else if (!data.mouseInChild) {
parentRemoveSubmenu(props.name);
}
}, DELAY);
}
if (deepDispatch) {
if (getParentSubMenu.value) {
parentHandleMouseleave?.(true);
}
}
}
onBeforeMount(() => {
subMenuEmitter.on('submenu:mouse-enter-child', () => {
data.mouseInChild = true;
isRemoveAllPopup.value = false;
clearTimeout(data.timeout!);
});
subMenuEmitter.on('submenu:mouse-leave-child', () => {
if (data.isChild) return;
data.mouseInChild = false;
clearTimeout(data.timeout!);
});
rootMenuEmitter.on(
'on-update-opened',
(data: boolean | (string | number)[] | Recordable) => {
if (unref(getCollapse)) return;
if (isBoolean(data)) {
state.opened = data;
return;
}
if (isObject(data) && rootProps.accordion) {
const { opend, parent, uidList } = data as Recordable;
if (parent === instance?.parent) {
state.opened = opend;
} else if (!uidList.includes(instance?.uid)) {
state.opened = false;
}
return;
function getEvents(deep: boolean) {
if (!unref(getCollapse)) {
return {};
}
return {
onMouseenter: handleMouseenter,
onMouseleave: () => handleMouseleave(deep)
};
}
if (props.name && Array.isArray(data)) {
state.opened = (data as (string | number)[]).includes(props.name);
function handleClick() {
const { disabled } = props;
if (disabled || unref(getCollapse)) return;
const opened = state.opened;
if (unref(getAccordion)) {
const { uidList } = getParentList();
rootMenuEmitter.emit('on-update-opened', {
opend: false,
parent: instance?.parent,
uidList: uidList
});
} else {
rootMenuEmitter.emit('open-name-change', {
name: props.name,
opened: !opened
});
}
state.opened = !opened;
}
},
);
rootMenuEmitter.on('on-update-active-name:submenu', (data: number[]) => {
if (instance?.uid) {
state.active = data.includes(instance?.uid);
}
});
});
function handleMouseenter() {
const disabled = props.disabled;
if (disabled) return;
function handleVisibleChange(visible: boolean) {
state.opened = visible;
}
subMenuEmitter.emit('submenu:mouse-enter-child');
// provide
provide<SubMenuProvider>(`subMenu:${instance?.uid}`, {
addSubMenu: parentAddSubmenu,
removeSubMenu: parentRemoveSubmenu,
getOpenNames: parentGetOpenNames,
removeAll: parentRemoveAll,
isRemoveAllPopup,
sliceIndex,
level: level + 1,
handleMouseleave,
props: rootProps,
});
const index = parentGetOpenNames().findIndex((item) => item === props.name);
return {
getClass,
prefixCls,
getCollapse,
getItemStyle,
handleClick,
handleVisibleChange,
getParentSubMenu,
getOverlayStyle,
getTheme,
getIsOpend,
getEvents,
getSubClass,
...toRefs(state),
...toRefs(data),
};
},
});
sliceIndex(index);
const isRoot = level === 0 && parentGetOpenNames().length === 2;
if (isRoot) {
parentRemoveAll();
}
data.isChild = parentGetOpenNames().includes(props.name);
clearTimeout(data.timeout!);
data.timeout = setTimeout(() => {
parentAddSubmenu(props.name);
}, DELAY);
}
function handleMouseleave(deepDispatch = false) {
const parentName = getParentMenu.value?.props.name;
if (!parentName) {
isRemoveAllPopup.value = true;
}
if (parentGetOpenNames().slice(-1)[0] === props.name) {
data.isChild = false;
}
subMenuEmitter.emit('submenu:mouse-leave-child');
if (data.timeout) {
clearTimeout(data.timeout!);
data.timeout = setTimeout(() => {
if (isRemoveAllPopup.value) {
parentRemoveAll();
} else if (!data.mouseInChild) {
parentRemoveSubmenu(props.name);
}
}, DELAY);
}
if (deepDispatch) {
if (getParentSubMenu.value) {
parentHandleMouseleave?.(true);
}
}
}
onBeforeMount(() => {
subMenuEmitter.on('submenu:mouse-enter-child', () => {
data.mouseInChild = true;
isRemoveAllPopup.value = false;
clearTimeout(data.timeout!);
});
subMenuEmitter.on('submenu:mouse-leave-child', () => {
if (data.isChild) return;
data.mouseInChild = false;
clearTimeout(data.timeout!);
});
rootMenuEmitter.on('on-update-opened', (data: boolean | (string | number)[] | Recordable) => {
if (unref(getCollapse)) return;
if (isBoolean(data)) {
state.opened = data;
return;
}
if (isObject(data) && rootProps.accordion) {
const { opend, parent, uidList } = data as Recordable;
if (parent === instance?.parent) {
state.opened = opend;
} else if (!uidList.includes(instance?.uid)) {
state.opened = false;
}
return;
}
if (props.name && Array.isArray(data)) {
state.opened = (data as (string | number)[]).includes(props.name);
}
});
rootMenuEmitter.on('on-update-active-name:submenu', (data: number[]) => {
if (instance?.uid) {
state.active = data.includes(instance?.uid);
}
});
});
function handleVisibleChange(visible: boolean) {
state.opened = visible;
}
// provide
provide<SubMenuProvider>(`subMenu:${instance?.uid}`, {
addSubMenu: parentAddSubmenu,
removeSubMenu: parentRemoveSubmenu,
getOpenNames: parentGetOpenNames,
removeAll: parentRemoveAll,
isRemoveAllPopup,
sliceIndex,
level: level + 1,
handleMouseleave,
props: rootProps
});
return {
getClass,
prefixCls,
getCollapse,
getItemStyle,
handleClick,
handleVisibleChange,
getParentSubMenu,
getOverlayStyle,
getTheme,
getIsOpend,
getEvents,
getSubClass,
...toRefs(state),
...toRefs(data)
};
}
});
</script>

View File

@ -2,76 +2,76 @@
@prefix-cls: ~'@{namespace}-menu';
.@{prefix-cls} {
&-dark&-vertical .@{simple-prefix-cls}__parent {
background-color: @sider-dark-darken-bg-color;
> .@{prefix-cls}-submenu-title {
background-color: @sider-dark-darken-bg-color;
&-dark&-vertical .@{simple-prefix-cls}__parent {
background-color: @sider-dark-darken-bg-color;
> .@{prefix-cls}-submenu-title {
background-color: @sider-dark-darken-bg-color;
}
}
}
&-dark&-vertical .@{simple-prefix-cls}__children,
&-dark&-popup .@{simple-prefix-cls}__children {
// background-color: @sider-dark-lighten-bg-color;
> .@{prefix-cls}-submenu-title {
background-color: @sider-dark-lighten-bg-color;
&-dark&-vertical .@{simple-prefix-cls}__children,
&-dark&-popup .@{simple-prefix-cls}__children {
// background-color: @sider-dark-lighten-bg-color;
> .@{prefix-cls}-submenu-title {
background-color: @sider-dark-lighten-bg-color;
}
}
}
.collapse-title {
overflow: hidden;
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.collapse-title {
overflow: hidden;
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.@{simple-prefix-cls} {
&-sub-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: all 0.3s;
}
&-tag {
position: absolute;
top: calc(50% - 8px);
right: 30px;
display: inline-block;
padding: 2px 3px;
margin-right: 4px;
font-size: 10px;
line-height: 14px;
color: #fff;
border-radius: 2px;
&--collapse {
top: 6px !important;
right: 2px;
&-sub-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: all 0.3s;
}
&--dot {
top: calc(50% - 2px);
width: 6px;
height: 6px;
padding: 0;
border-radius: 50%;
}
&-tag {
position: absolute;
top: calc(50% - 8px);
right: 30px;
display: inline-block;
padding: 2px 3px;
margin-right: 4px;
font-size: 10px;
line-height: 14px;
color: #fff;
border-radius: 2px;
&--primary {
background-color: @primary-color;
}
&--collapse {
top: 6px !important;
right: 2px;
}
&--error {
background-color: @error-color;
}
&--dot {
top: calc(50% - 2px);
width: 6px;
height: 6px;
padding: 0;
border-radius: 50%;
}
&--success {
background-color: @success-color;
}
&--primary {
background-color: @primary-color;
}
&--warn {
background-color: @warning-color;
&--error {
background-color: @error-color;
}
&--success {
background-color: @success-color;
}
&--warn {
background-color: @warning-color;
}
}
}
}