DropDown 下拉菜单
下拉菜单组件是一个可以将页面上比较冗杂的操作收纳在一个点,以便节省页面空间,达到整洁美观的目的。
Antd的下拉菜单组件中有一个点,就是他的内部元素必须是Antd的Menu组件,感觉有点捆绑的意思。
DropDownProps
这里留一个小问题,为什么触发方式是一个数组,而不是单个的
export interface DropDownProps {
trigger?: ('click' | 'hover')[]; // 触发方式
overlay: React.ReactNode; // 下拉菜单所承载的内容元素,要求为Antd的Menu组件
style?: React.CSSProperties; // 行内样式
onVisibleChange?: (visible?: boolean) => void; // 监听下拉菜单出现/消失
visible?: boolean; // 菜单是否显示
disabled?: boolean; // 菜单是否可以用
align?: Object; // 这个参数目前没有被使用
getPopupContainer?: (triggerNode: Element) => HTMLElement; // 渲染的挂载点,默认为body
prefixCls?: string; // 样式类的命名前缀
className?: string; // 样式
placement?: 'topLeft' | 'topCenter' | 'topRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight';
// 弹出框与触发点的对齐方式
}
直接看代码
因为这个组件主要使用的是rc-dropdown组件
所以这里只是对其参数做了一些封装,比较简单。
export default class Dropdown extends React.Component<DropDownProps, any> {
static Button: typeof DropdownButton;
static defaultProps = {
prefixCls: 'ant-dropdown',
mouseEnterDelay: 0.15,
mouseLeaveDelay: 0.1,
placement: 'bottomLeft',
};
// 设定一个动画效果名称
getTransitionName() {
const { placement = '' } = this.props;
// js的indexOf()可以使用在Array上也可以使用在String上
// 使用方法一样,第一个参数是匹配的对象,第二个参数是从哪里开始匹配
if (placement.indexOf('top') >= 0) {
return 'slide-down';
}
return 'slide-up';
}
componentDidMount() {
// 这里就在检测菜单内容是否是antd的menu组件,并且检测menu组件的样式
const { overlay } = this.props;
const overlayProps = (overlay as any).props as any;
// warning函数还是和之前学习的一样的用法
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
);
}
render() {
const { children, prefixCls, overlay, trigger, disabled } = this.props;
// 将dropdown包裹的触发器加以封装,再渲染
const dropdownTrigger = cloneElement(children as any, {
className: classNames((children as any).props.className, `${prefixCls}-trigger`),
disabled,
});
// menu cannot be selectable in dropdown defaultly
const overlayProps = overlay && (overlay as any).props;
const selectable = (overlayProps && 'selectable' in overlayProps)
? overlayProps.selectable : false;
// 同样的将dropdown包裹的内容加以封装,再渲染
const fixedModeOverlay = cloneElement(overlay as any, {
mode: 'vertical',
selectable,
});
return (
// 最后将所有参数传入rc-dropdown组件
<RcDropdown {...this.props} transitionName={this.getTransitionName()} trigger={disabled ? [] : trigger} overlay={fixedModeOverlay} > {dropdownTrigger} </RcDropdown>
);
}
}
DropdownButton
这个组件是一个带按钮的下拉菜单组件,其实其原理就是使用的之前所讲的ButtonGroup来进行组合的一个组件。
想要了解ButtonGroup组件的可以点击这里
DropdownButtonProps
这个组件的props继承了两个其他组件的props,这是typescript的interface的一个特性,可以继承多个,来形成一个新的。
export interface DropdownButtonProps extends ButtonGroupProps, DropDownProps {
type?: 'primary' | 'ghost' | 'dashed'; // 按钮类型
disabled?: boolean; // 是否禁用
onClick?: React.MouseEventHandler<any>; // 点击事件
children?: any; // 子节点
}
Render()
从render函数就可以看出这个组件就是antd为了方便,为大家封装好了的一个带下拉菜单的按钮组件
render() {
const {
type, disabled, onClick, children,
prefixCls, className, overlay, trigger, align,
visible, onVisibleChange, placement, getPopupContainer,
...restProps,
} = this.props;
const dropdownProps = {
align,
overlay,
trigger: disabled ? [] : trigger,
onVisibleChange,
placement,
getPopupContainer,
};
if ('visible' in this.props) {
(dropdownProps as any).visible = visible;
}
return (
<ButtonGroup {...restProps} className={classNames(prefixCls, className)} > <Button type={type} disabled={disabled} onClick={onClick} > {children} </Button> <Dropdown {...dropdownProps}> <Button type={type} disabled={disabled}> <Icon type="down" /> </Button> </Dropdown> </ButtonGroup>
);
}
这就完了?怎么可能,还不过瘾
写到这里就完了么?是滴,这一节就完了,因为查看了一下rc-dropdown的实现,然后根据平常看代码的习惯
从render()函数入口发现这一段代码
render() {
const {
prefixCls, children,
transitionName, animation,
align, placement, getPopupContainer,
showAction, hideAction,
overlayClassName, overlayStyle,
trigger, ...otherProps,
} = this.props;
return (
<Trigger
{...otherProps}
prefixCls={prefixCls}
ref={this.saveTrigger}
popupClassName={overlayClassName}
popupStyle={overlayStyle}
builtinPlacements={placements}
action={trigger}
showAction={showAction}
hideAction={hideAction}
popupPlacement={placement}
popupAlign={align}
popupTransitionName={transitionName}
popupAnimation={animation}
popupVisible={this.state.visible}
afterPopupVisibleChange={this.afterVisibleChange}
popup={this.getMenuElement()}
onPopupVisibleChange={this.onVisibleChange}
getPopupContainer={getPopupContainer}
>
{children}
</Trigger>
);
}
然后再看到Trigger
这个组件,居然是另外一个库rc-trigger
然后在看了rc-trigger
的实现之后,才知道原来tigger组件才是下拉菜单的核心。
所以还没完呢,只是需要讲解的太多,不适合在一篇文章中讲全面,所以敬请期待下一篇文章,
我们将会学习rc-trigger组件的实现,之后会再写一篇rc-dropdown的组件实现解读,
最后看完这三篇文章,再倒过来重温一遍,你将会学到怎么样一层层的包装组件,将一个基础组件包装成为一个高级组件的过程。
今天的文章antd源码解读(8)- Dropdown分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19589.html