import './index.less' import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue' import { VueNodeOrRenderPropType, WithFalseVueNodeOrRenderPropType } from '#/types' import { Layout, Menu, MenuItem } from 'ant-design-vue' import BaseMenu, { baseMenuProps } from './BaseMenu' import type { VueNodeOrRender } from '#/types' import type { WithFalse } from '../../types' import type { CSSProperties, ExtractPropTypes, FunctionalComponent, PropType, Slots } from 'vue' import type { SiderProps } from 'ant-design-vue' import type { CollapsedButtonRender, MenuContentRender, MenuExtraReander, MenuFootRender, MenuHeaderRender } from '../../renderTypes' import { getVueNode, getRender } from '../../utils' export const siderMenuProps = () => ({ ...baseMenuProps(), logo: { type: VueNodeOrRenderPropType as PropType, default: undefined }, siderWidth: { type: Number, default: 208 }, /** * 菜单 logo 和 title 区域的渲染 * * @example 不要logo : menuHeaderRender={(logo,title)=> title} * @example 不要title : menuHeaderRender={(logo,title)=> logo} * @example 展开的时候显示title,收起显示 logo: menuHeaderRender={(logo,title,props)=> props.collapsed ? logo : title} * @example 不要这个区域了 : menuHeaderRender={false} */ menuHeaderRender: { type: WithFalseVueNodeOrRenderPropType as PropType>, default: undefined }, /** * 侧边菜单底部的配置,可以增加一些底部操作 * * @example 底部增加超链接 menuFooterRender={()=>pro.ant.design} * @example 根据收起展开配置不同的 dom menuFooterRender={()=>collapsed? null :pro.ant.design} */ menuFooterRender: { type: WithFalseVueNodeOrRenderPropType as PropType>, default: undefined }, /** * 侧边菜单,菜单区域的处理,可以单独处理菜单的dom * * @example 增加菜单区域的背景颜色 menuContentRender={(props,defaultDom)=>
{defaultDom}
} * @example 某些情况下不显示菜单 menuContentRender={(props)=> return
不显示菜单
} */ menuContentRender: { type: WithFalseVueNodeOrRenderPropType as PropType>, default: undefined }, /** * 侧边菜单 title 和 logo 下面区域的渲染,一般会增加个搜索框 * * @example 增加一个搜索框 menuExtraRender={()=>()} * @example 根据收起展开配置不同的 dom: menuExtraRender={()=>collapsed? null : } */ menuExtraRender: { type: WithFalseVueNodeOrRenderPropType as PropType>, default: false }, /** * 自定义展开收起按钮的渲染 * * @example 使用文字渲染 collapsedButtonRender={(collapsed)=>collapsed?"展开":"收起"})} * @example 使用icon渲染 collapsedButtonRender={(collapsed)=>collapsed?:} * @example 不渲染按钮 collapsedButtonRender={false} */ collapsedButtonRender: { type: WithFalseVueNodeOrRenderPropType as PropType>, default: undefined }, /** * 菜单是否收起的断点,设置成false 可以禁用 * * @example 禁用断点 breakpoint={false} * @example 最小的屏幕再收起 breakpoint={'xs'} */ breakpoint: { type: [String, Boolean] as PropType, default: 'lg' }, /** * 菜单顶部logo 和 title 区域的点击事件 * * @example 点击跳转到首页 onMenuHeaderClick={()=>{ history.push('/') }} */ onMenuHeaderClick: { type: Function as PropType<(e: MouseEvent) => void>, default: undefined }, /** * 侧边菜单底部的一些快捷链接 * * @example links={[ 访问官网 , 帮助 ]} */ links: { type: VueNodeOrRenderPropType as PropType, default: undefined }, // TODO 这个放到事件里面 onOpenChange: { type: Function as PropType<(openKeys: WithFalse) => void>, default: undefined }, getContainer: { type: Boolean, default: false }, logoStyle: { type: Object as PropType, default: () => undefined }, hide: { type: Boolean, default: undefined } }) export type SiderMenuProps = Partial>> export const privateSiderMenuProps = () => ({ matchMenuKeys: Array as PropType }) export type PrivateSiderMenuProps = Partial< ExtractPropTypes> > export const defaultRenderLogo = ( logo: VueNodeOrRender | (() => VueNodeOrRender) ): VueNodeOrRender => { if (typeof logo === 'string') { return logo } if (typeof logo === 'function') { return logo() } return logo } export const defaultRenderLogoAndTitle = ( props: SiderMenuProps, slots: Slots, renderKey = 'menuHeaderRender' ): VueNodeOrRender => { if (props.layout === 'mix' && renderKey === 'menuHeaderRender') { return null } const renderFunction = getRender(props, slots, renderKey) if (renderFunction === false) { return null } const logRender = getRender(props, slots, 'logo') const logoDom = defaultRenderLogo(logRender) const titleRender = getVueNode(props.title, slots.title) const titleDom =

{titleRender ?? 'Ball Cat'}

if (renderFunction) { // when collapsed, no render title return renderFunction(props, logoDom, props.collapsed ? null : titleDom) } return ( {logoDom} {props.collapsed ? null : titleDom} ) } export const defaultRenderCollapsedButton = (collapsed?: boolean) => collapsed ? : function getCollapsedButtonRender(props: SiderMenuProps & PrivateSiderMenuProps, slots: Slots) { if (props.collapsedButtonRender == false) { return false } const render = getRender(props, slots, 'collapsedButtonRender') return render || defaultRenderCollapsedButton } const SiderMenu: FunctionalComponent = ( props, { slots, attrs } ) => { const baseClassName = `${props.prefixCls}-sider` const siderClassName = { [`${baseClassName}`]: true, [`${baseClassName}-fixed`]: props.fixSiderbar, [`${baseClassName}-layout-${props.layout}`]: props.layout && !props.isMobile, [`${baseClassName}-light`]: props.theme !== 'dark' } const headerDom = defaultRenderLogoAndTitle(props, slots) // const { flatMenuKeys } = MenuCounter.useContainer() const flatMenuKeys: string[] = [] const extraDom = props.menuExtraRender && props.menuExtraRender(props) const menuDom = props.menuContentRender !== false && flatMenuKeys && ( ) const menuRenderDom = props.menuContentRender ? props.menuContentRender(props, menuDom) : menuDom const collapsedButtonRender = getCollapsedButtonRender(props, slots) const menuFooterRender = getRender(props, slots, 'menuFooterRender') return ( <> {props.fixSiderbar && (
)} { if (props.isMobile) return props.onCollapse?.(collapse) }} collapsedWidth={48} style={{ overflow: 'hidden', paddingTop: props.layout === 'mix' && !props.isMobile ? `${props.headerHeight}px` : undefined, ...(attrs.style as CSSProperties) }} width={props.siderWidth} theme={props.theme} class={siderClassName} > {headerDom && ( )} {extraDom && (
{extraDom}
)}
{menuRenderDom}
{collapsedButtonRender !== false && ( { if (props.onCollapse) { props.onCollapse(!props.collapsed) } }} > {collapsedButtonRender(props.collapsed)} )}
{menuFooterRender && (
{menuFooterRender(props)}
)}
) } export default SiderMenu