Commit f9accd25 authored by Sendya's avatar Sendya

fix: menu selectedKeys abort

parent 17e764ca
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
v-model:openKeys="baseState.openKeys" v-model:openKeys="baseState.openKeys"
v-bind="state" v-bind="state"
:loading="loading" :loading="loading"
:collapsed-button-render="false"
:breadcrumb="{ routes: breadcrumb }" :breadcrumb="{ routes: breadcrumb }"
> >
<!-- only work layout `Side` --> <!-- only work layout `Side` -->
...@@ -29,6 +28,23 @@ ...@@ -29,6 +28,23 @@
{{ route.breadcrumbName }} {{ route.breadcrumbName }}
</router-link> </router-link>
</template> </template>
<!-- custom menu-item -->
<template #menuItemRender="{ item, icon }">
<a-menu-item
:key="item.path"
:disabled="item.meta?.disabled"
:danger="item.meta?.danger"
:icon="icon"
>
<router-link :to="{ path: item.path }">
<div class="a-menu-item-title">
<a-badge count="5" dot>
{{ item.meta.title }}
</a-badge>
</div>
</router-link>
</a-menu-item>
</template>
<!-- content begin --> <!-- content begin -->
<router-view /> <router-view />
<!-- content end --> <!-- content end -->
...@@ -61,7 +77,7 @@ ...@@ -61,7 +77,7 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, reactive, ref, watchEffect } from 'vue'; import { computed, defineComponent, reactive, ref, watchEffect } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { Button, Switch, Select, Space } from 'ant-design-vue'; import { Button, Switch, Select, Space, Badge, Menu } from 'ant-design-vue';
import { getMenuData, clearMenuItem, FooterToolbar } from '@ant-design-vue/pro-layout'; import { getMenuData, clearMenuItem, FooterToolbar } from '@ant-design-vue/pro-layout';
import type { RouteContextProps } from '@ant-design-vue/pro-layout'; import type { RouteContextProps } from '@ant-design-vue/pro-layout';
...@@ -76,6 +92,9 @@ export default defineComponent({ ...@@ -76,6 +92,9 @@ export default defineComponent({
[Select.name]: Select, [Select.name]: Select,
[Select.Option.displayName!]: Select.Option, [Select.Option.displayName!]: Select.Option,
[Space.name]: Space, [Space.name]: Space,
[Badge.name]: Badge,
[Menu.Item.name]: Menu.Item,
}, },
setup() { setup() {
const loading = ref(false); const loading = ref(false);
...@@ -134,7 +153,7 @@ export default defineComponent({ ...@@ -134,7 +153,7 @@ export default defineComponent({
state, state,
loading, loading,
breadcrumb, breadcrumb,
handlePageLoadingClick, handlePageLoadingClick,
handleCollapsed, handleCollapsed,
}; };
......
import { computed, reactive, unref, provide, defineComponent, toRefs, watch } from 'vue'; import { computed, reactive, unref, provide, defineComponent, toRefs } from 'vue';
import type { CSSProperties, PropType, ExtractPropTypes } from 'vue'; import type { CSSProperties, PropType, ExtractPropTypes } from 'vue';
import 'ant-design-vue/es/layout/style'; import 'ant-design-vue/es/layout/style';
...@@ -14,12 +14,12 @@ import { default as SiderMenuWrapper, siderMenuProps } from './SiderMenu'; ...@@ -14,12 +14,12 @@ import { default as SiderMenuWrapper, siderMenuProps } from './SiderMenu';
import { WrapContent } from './WrapContent'; import { WrapContent } from './WrapContent';
import globalHeaderProps from './GlobalHeader/headerProps'; import globalHeaderProps from './GlobalHeader/headerProps';
import { HeaderView as Header, headerViewProps } from './Header'; import { HeaderView as Header, headerViewProps } from './Header';
import { getPropsSlot, PropTypes } from './utils'; import { getPropsSlot, getPropsSlotfn, PropTypes } from './utils';
import type { CustomRender, FormatMessage, WithFalse } from './typings'; import type { CustomRender, FormatMessage, WithFalse } from './typings';
import './BasicLayout.less'; import './BasicLayout.less';
import PageLoading from '@/PageLoading'; import PageLoading from './PageLoading';
export const basicLayoutProps = { export const basicLayoutProps = {
...defaultSettingProps, ...defaultSettingProps,
...@@ -172,13 +172,20 @@ const ProLayout = defineComponent({ ...@@ -172,13 +172,20 @@ const ProLayout = defineComponent({
const customHeaderRender = getPropsSlot(slots, props, 'headerRender'); const customHeaderRender = getPropsSlot(slots, props, 'headerRender');
const menuHeaderRender = getPropsSlot(slots, props, 'menuHeaderRender'); const menuHeaderRender = getPropsSlot(slots, props, 'menuHeaderRender');
const footerRender = getPropsSlot(slots, props, 'footerRender'); const footerRender = getPropsSlot(slots, props, 'footerRender');
// const menuRender = getPropsSlot(slots, props, 'menuRender'); const breadcrumbRender = getPropsSlotfn(slots, props, 'breadcrumbRender');
const breadcrumbRender = props.breadcrumbRender || slots.breadcrumbRender; // menu render
const menuItemRender = getPropsSlotfn(slots, props, 'menuItemRender');
const subMenuItemRender = getPropsSlotfn(slots, props, 'subMenuItemRender');
const menuRenders = {
menuItemRender,
subMenuItemRender,
};
const headerDom = computed(() => const headerDom = computed(() =>
headerRender( headerRender(
{ {
...props, ...props,
...menuRenders,
hasSiderMenu: !isTop.value, hasSiderMenu: !isTop.value,
menuData: props.menuData, menuData: props.menuData,
isMobile: unref(isMobile), isMobile: unref(isMobile),
...@@ -235,6 +242,7 @@ const ProLayout = defineComponent({ ...@@ -235,6 +242,7 @@ const ProLayout = defineComponent({
{!isTop.value && ( {!isTop.value && (
<SiderMenuWrapper <SiderMenuWrapper
{...restProps.value} {...restProps.value}
{...menuRenders}
isMobile={isMobile.value} isMobile={isMobile.value}
menuHeaderRender={menuHeaderRender} menuHeaderRender={menuHeaderRender}
collapsedButtonRender={collapsedButtonRender} collapsedButtonRender={collapsedButtonRender}
......
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
PropType, PropType,
isVNode, isVNode,
ExtractPropTypes, ExtractPropTypes,
ConcreteComponent,
} from 'vue'; } from 'vue';
import { createFromIconfontCN } from '@ant-design/icons-vue'; import { createFromIconfontCN } from '@ant-design/icons-vue';
import 'ant-design-vue/es/menu/style'; import 'ant-design-vue/es/menu/style';
...@@ -30,8 +31,12 @@ export function useRootSubmenuKeys(menus: MenuDataItem[]): ComputedRef<string[]> ...@@ -30,8 +31,12 @@ export function useRootSubmenuKeys(menus: MenuDataItem[]): ComputedRef<string[]>
} }
export interface CustomMenuRender { export interface CustomMenuRender {
menuItemRender?: WithFalse<(item: MenuDataItem) => CustomRender>; menuItemRender?: WithFalse<
subMenuItemRender?: WithFalse<(item: MenuDataItem, children?: CustomRender[]) => CustomRender>; (args: { item: MenuDataItem; title?: JSX.Element; icon?: JSX.Element }) => CustomRender
>;
subMenuItemRender?: WithFalse<
(args: { item: MenuDataItem; children?: CustomRender[] }) => CustomRender
>;
} }
// vue props // vue props
...@@ -130,9 +135,12 @@ LazyIcon.props = { ...@@ -130,9 +135,12 @@ LazyIcon.props = {
class MenuUtil { class MenuUtil {
props: BaseMenuProps; props: BaseMenuProps;
RouterLink: ConcreteComponent;
constructor(props: BaseMenuProps) { constructor(props: BaseMenuProps) {
this.props = props; this.props = props;
this.RouterLink = resolveComponent('router-link') as ConcreteComponent;
} }
getNavMenuItems = (menusData: MenuDataItem[] = []) => { getNavMenuItems = (menusData: MenuDataItem[] = []) => {
...@@ -147,7 +155,10 @@ class MenuUtil { ...@@ -147,7 +155,10 @@ class MenuUtil {
!item?.meta?.hideChildrenInMenu !item?.meta?.hideChildrenInMenu
) { ) {
if (this.props.subMenuItemRender) { if (this.props.subMenuItemRender) {
return this.props.subMenuItemRender(item, this.getNavMenuItems(item.children)) as VNode; return this.props.subMenuItemRender({
item,
children: this.getNavMenuItems(item.children),
}) as VNode;
} }
const { prefixCls, locale } = this.props; const { prefixCls, locale } = this.props;
const menuTitle = (locale && locale(item.meta?.title)) || item.meta?.title; const menuTitle = (locale && locale(item.meta?.title)) || item.meta?.title;
...@@ -176,7 +187,8 @@ class MenuUtil { ...@@ -176,7 +187,8 @@ class MenuUtil {
const [title, icon] = this.getMenuItem(item); const [title, icon] = this.getMenuItem(item);
return ( return (
((this.props.menuItemRender && this.props.menuItemRender(item)) as VNode) || ( ((this.props.menuItemRender &&
this.props.menuItemRender({ item, title, icon })) as VNode) || (
<Menu.Item <Menu.Item
disabled={item.meta?.disabled} disabled={item.meta?.disabled}
danger={item.meta?.danger} danger={item.meta?.danger}
...@@ -193,7 +205,7 @@ class MenuUtil { ...@@ -193,7 +205,7 @@ class MenuUtil {
const meta = { ...item.meta }; const meta = { ...item.meta };
const target = (meta.target || null) as string | null; const target = (meta.target || null) as string | null;
const hasUrl = isUrl(item.path); const hasUrl = isUrl(item.path);
const CustomTag: any = (target && 'a') || resolveComponent('router-link'); const CustomTag: any = (target && 'a') || this.RouterLink;
const props = { to: { name: item.name } }; const props = { to: { name: item.name } };
const attrs = hasUrl || target ? { ...item.meta, href: item.path, target } : {}; const attrs = hasUrl || target ? { ...item.meta, href: item.path, target } : {};
...@@ -209,13 +221,7 @@ class MenuUtil { ...@@ -209,13 +221,7 @@ class MenuUtil {
</CustomTag> </CustomTag>
); );
const icon = const icon = (item.meta?.icon && <LazyIcon icon={item.meta.icon} />) || undefined;
(item.meta?.icon && (
<CustomTag {...attrs} {...props} class={`${prefixCls}-menu-item`}>
<LazyIcon icon={item.meta.icon} />
</CustomTag>
)) ||
null;
return [defaultTitle, icon]; return [defaultTitle, icon];
}; };
......
...@@ -4,6 +4,7 @@ import { ...@@ -4,6 +4,7 @@ import {
ExtractPropTypes, ExtractPropTypes,
PropType, PropType,
CSSProperties, CSSProperties,
unref,
} from 'vue'; } from 'vue';
import 'ant-design-vue/es/layout/style'; import 'ant-design-vue/es/layout/style';
import Layout from 'ant-design-vue/es/layout'; import Layout from 'ant-design-vue/es/layout';
...@@ -161,8 +162,9 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => { ...@@ -161,8 +162,9 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
const context = useRouteContext(); const context = useRouteContext();
const { getPrefixCls } = context; const { getPrefixCls } = context;
const baseClassName = getPrefixCls('sider'); const baseClassName = getPrefixCls('sider');
// const isMix = computed(() => props.layout === 'mix'); const hasSplitMenu = computed(() => props.layout === 'mix' && props.splitMenus);
// const fixed = computed(() => context.fixSiderbar); const hasSide = computed(() => props.layout === 'mix' || props.layout === 'side' || false);
const sTheme = computed(() => (props.layout === 'mix' && 'light') || props.navTheme); const sTheme = computed(() => (props.layout === 'mix' && 'light') || props.navTheme);
const sSideWidth = computed(() => (props.collapsed ? props.collapsedWidth : props.siderWidth)); const sSideWidth = computed(() => (props.collapsed ? props.collapsedWidth : props.siderWidth));
const classNames = computed(() => { const classNames = computed(() => {
...@@ -173,13 +175,18 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => { ...@@ -173,13 +175,18 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
[`${baseClassName}-fixed`]: context.fixSiderbar, [`${baseClassName}-fixed`]: context.fixSiderbar,
}; };
}); });
const hasSide = computed( const flatMenuData = computed(
() => ((props.layout === 'mix' || props.layout === 'side') && props.splitMenus) || false, () => (hasSide.value && getMenuFirstChildren(context.menuData, context.selectedKeys[0])) || [],
); );
const flatMenuData = computed(() => { const handleSelect = ($event: string[]) => {
console.log('context.selectedKeys[0]', context.selectedKeys[0]); if (props.onSelect) {
return (hasSide.value && getMenuFirstChildren(context.menuData, context.selectedKeys[0])) || []; if (unref(hasSplitMenu)) {
}); props.onSelect([context.selectedKeys[0], ...$event]);
return;
}
props.onSelect($event);
}
};
// call menuHeaderRender // call menuHeaderRender
const headerDom = defaultRenderLogoAndTitle(props); const headerDom = defaultRenderLogoAndTitle(props);
const extraDom = menuExtraRender && menuExtraRender(props); const extraDom = menuExtraRender && menuExtraRender(props);
...@@ -192,7 +199,7 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => { ...@@ -192,7 +199,7 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
locale={props.locale || context.locale} locale={props.locale || context.locale}
theme={sTheme.value === 'realDark' ? 'dark' : sTheme.value} theme={sTheme.value === 'realDark' ? 'dark' : sTheme.value}
mode="inline" mode="inline"
menuData={hasSide.value ? flatMenuData.value : context.menuData} menuData={hasSplitMenu.value ? flatMenuData.value : context.menuData}
collapsed={props.collapsed} collapsed={props.collapsed}
openKeys={context.openKeys} openKeys={context.openKeys}
selectedKeys={context.selectedKeys} selectedKeys={context.selectedKeys}
...@@ -205,7 +212,7 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => { ...@@ -205,7 +212,7 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
class={`${baseClassName}-menu`} class={`${baseClassName}-menu`}
{...{ {...{
'onUpdate:openKeys': ($event: string[]) => onOpenKeys && onOpenKeys($event), 'onUpdate:openKeys': ($event: string[]) => onOpenKeys && onOpenKeys($event),
'onUpdate:selectedKeys': ($event: string[]) => onSelect && onSelect($event), 'onUpdate:selectedKeys': handleSelect,
}} }}
/> />
); );
......
...@@ -27,5 +27,3 @@ export type { WaterMarkProps } from './WaterMark'; ...@@ -27,5 +27,3 @@ export type { WaterMarkProps } from './WaterMark';
export { default } from './BasicLayout'; export { default } from './BasicLayout';
// export { default as ProLayout } from './BasicLayout'; // export { default as ProLayout } from './BasicLayout';
export type { BasicLayoutProps } from './BasicLayout'; export type { BasicLayoutProps } from './BasicLayout';
export { default as PageLoading } from './Pageloading';
...@@ -71,6 +71,10 @@ export function getPropsSlot(slots: Slots, props: Record<string, any>, prop = 'd ...@@ -71,6 +71,10 @@ export function getPropsSlot(slots: Slots, props: Record<string, any>, prop = 'd
return props[prop] || slots[prop]?.(); return props[prop] || slots[prop]?.();
} }
export function getPropsSlotfn(slots: Slots, props: Record<string, any>, prop = 'default') {
return props[prop] || slots[prop];
}
export const PropRenderType = { export const PropRenderType = {
type: [Function, Boolean], type: [Function, Boolean],
default: () => undefined, default: () => undefined,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment