Commit 2b8873d9 authored by Sendya's avatar Sendya

refactor: BaseMenu render functional

parent c6275e89
...@@ -42,8 +42,12 @@ export interface BaseMenuProps extends Partial<PureSettings>, PrivateSiderMenuPr ...@@ -42,8 +42,12 @@ export interface BaseMenuProps extends Partial<PureSettings>, PrivateSiderMenuPr
} }
// vue props // vue props
export const VueBaseMenuProps = { export const baseMenuProps = {
locale: Boolean, locale: Boolean,
i18n: {
type: Function as PropType<FormatMessage>,
default: (t: string): string => t,
},
menuData: Array as PropType<MenuDataItem[]>, menuData: Array as PropType<MenuDataItem[]>,
// top-nav-header: horizontal // top-nav-header: horizontal
mode: { mode: {
...@@ -131,8 +135,12 @@ const IconFont = createFromIconfontCN({ ...@@ -131,8 +135,12 @@ const IconFont = createFromIconfontCN({
scriptUrl: defaultSettings.iconfontUrl, scriptUrl: defaultSettings.iconfontUrl,
}); });
const LazyIcon = (props: any) => { const LazyIcon = (props: {
const { icon, prefixCls } = props; icon: VNode | string;
iconPrefixes?: string;
prefixCls?: string;
}) => {
const { icon, iconPrefixes = 'icon-', prefixCls = 'ant-pro' } = props;
if (!icon) { if (!icon) {
return null; return null;
} }
...@@ -140,33 +148,105 @@ const LazyIcon = (props: any) => { ...@@ -140,33 +148,105 @@ const LazyIcon = (props: any) => {
if (isUrl(icon) || isImg(icon)) { if (isUrl(icon) || isImg(icon)) {
return <img src={icon} alt="icon" class={`${prefixCls}-sider-menu-icon`} />; return <img src={icon} alt="icon" class={`${prefixCls}-sider-menu-icon`} />;
} }
if (icon.startsWith('icon-')) { if (icon.startsWith(iconPrefixes)) {
return <IconFont type={icon} />; return <IconFont type={icon} />;
} }
} }
if (isVNode(icon)) { if (isVNode(icon)) {
return icon; return icon;
} }
const LazyIcon = resolveComponent(icon) as any; const DynamicIcon = resolveComponent(icon) as any;
return (typeof LazyIcon === 'function' && <LazyIcon />) || null; return (typeof LazyIcon === 'function' && <DynamicIcon />) || null;
}; };
LazyIcon.icon = { LazyIcon.props = {
type: [String, Function, Object] as PropType<string | Function | VNodeChild | JSX.Element>, icon: {
type: [String, Function, Object] as PropType<string | Function | VNode | JSX.Element>,
},
iconPrefixes: String,
prefixCls: String,
}; };
class MenuUtil {
props: BaseMenuProps;
constructor(props: BaseMenuProps) {
this.props = props;
}
getNavMenuItems = (menusData: MenuDataItem[] = [], isChildren: boolean) => {
return menusData.map(item => this.getSubMenuOrItem(item, isChildren)).filter(item => item);
}
getSubMenuOrItem = (item: MenuDataItem, isChildren: boolean) => {
if (Array.isArray(item.children)
&& item.children.length > 0
&& !item?.meta?.hideInMenu) {
const { prefixCls, i18n } = this.props;
const menuTitle = i18n && i18n(item.meta?.title) || item.meta?.title;
const defaultTitle = item?.meta.icon ? (
<span class={`${prefixCls}-menu-item`}>
{!isChildren && <LazyIcon icon={item.meta.icon} />}
<span class={`${prefixCls}-menu-item-title`}>{menuTitle}</span>
</span>
) : (
<span class={`${prefixCls}-menu-item`}>{menuTitle}</span>
);
const MenuComponent = item.meta?.type === 'group' ? Menu.ItemGroup : Menu.SubMenu;
return (
<MenuComponent title={defaultTitle} key={item.path}>
{this.getNavMenuItems(item.children, true)}
</MenuComponent>
);
}
return (
<Menu.Item
inlineIndent={24}
disabled={item.meta?.disabled}
key={item.path}
// onClick={}
>
{this.getMenuItem(item, isChildren)}
</Menu.Item>
);
}
getMenuItem = (item: MenuDataItem, isChildren: boolean) => {
const meta = Object.assign({}, item.meta);
const target = meta.target || null;
const hasUrl = isUrl(item.path);
const CustomTag: any = resolveComponent((target && 'a') || 'router-link');
const props = { to: { name: item.name } };
const attrs = hasUrl || target ? { href: item.path, target: target } : {};
const { prefixCls, i18n } = this.props;
const menuTitle = i18n && i18n(item.meta?.title) || item.meta?.title;
const defaultTitle = item?.meta.icon ? (
<span class={`${prefixCls}-menu-item`}>
<CustomTag {...attrs} {...props}>
{!isChildren && <LazyIcon icon={item.meta.icon} />}
<span class={`${prefixCls}-menu-item-title`}>{menuTitle}</span>
</CustomTag>
</span>
) : (
<span class={`${prefixCls}-menu-item`}>{menuTitle}</span>
);
return defaultTitle;
}
conversionPath = (path: string) => {
if (path && path.indexOf('http') === 0) {
return path;
}
return `/${path || ''}`.replace(/\/+/g, '/');
};
}
export default defineComponent({ export default defineComponent({
name: 'BaseMenu', name: 'BaseMenu',
props: Object.assign( props: baseMenuProps,
{},
{
i18n: {
type: Function as PropType<FormatMessage>,
default: (t: string): string => t,
},
},
VueBaseMenuProps,
),
emits: ['update:openKeys', 'update:selectedKeys'], emits: ['update:openKeys', 'update:selectedKeys'],
setup(props, { emit }) { setup(props, { emit }) {
const { mode, i18n } = toRefs(props); const { mode, i18n } = toRefs(props);
...@@ -184,6 +264,8 @@ export default defineComponent({ ...@@ -184,6 +264,8 @@ export default defineComponent({
}): void => { }): void => {
emit('update:selectedKeys', params.selectedKeys); emit('update:selectedKeys', params.selectedKeys);
}; };
// TODO :: add `Menu` onClick custom handle.
return () => ( return () => (
<Menu <Menu
key="Menu" key="Menu"
......
...@@ -18,7 +18,7 @@ export { ...@@ -18,7 +18,7 @@ export {
MenuMode, MenuMode,
OpenEventHandler, OpenEventHandler,
SelectInfo, SelectInfo,
VueBaseMenuProps, baseMenuProps,
} from './SiderMenu/BaseMenu'; } from './SiderMenu/BaseMenu';
export { default } from './BasicLayout'; export { default } from './BasicLayout';
import { VNodeChild } from 'vue'; import { VNode } from 'vue';
// define global types // define global types
export type RenderVNodeType = VNodeChild | Element | JSX.Element; export type RenderVNodeType = VNode | Element | JSX.Element;
export type MenuTheme = 'dark' | 'light'; export type MenuTheme = 'dark' | 'light';
...@@ -15,7 +15,11 @@ export interface MetaRecord { ...@@ -15,7 +15,11 @@ export interface MetaRecord {
/** /**
* @name 菜单的icon * @name 菜单的icon
*/ */
icon?: string | VNodeChild | JSX.Element; icon?: string | VNode;
/**
* @type 有 children 的菜单的组件类型 可选值 'group'
*/
type?: string;
/** /**
* @name 自定义菜单的国际化 key,如果没有则返回自身 * @name 自定义菜单的国际化 key,如果没有则返回自身
*/ */
......
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