下拉菜單組件是一個能夠將頁面上比較冗雜的操做收納在一個點,以便節省頁面空間,達到整潔美觀的目的。react
Antd的下拉菜單組件中有一個點,就是他的內部元素必須是Antd的Menu組件,感受有點捆綁的意思。git
這裏留一個小問題,爲何觸發方式是一個數組,而不是單個的github
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組件
因此這裏只是對其參數作了一些封裝,比較簡單。typescript
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>
);
}
}複製代碼
這個組件是一個帶按鈕的下拉菜單組件,其實其原理就是使用的以前所講的ButtonGroup來進行組合的一個組件。數組
想要了解ButtonGroup組件的能夠點擊這裏antd
這個組件的props繼承了兩個其餘組件的props,這是typescript的interface的一個特性,能夠繼承多個,來造成一個新的。ide
export interface DropdownButtonProps extends ButtonGroupProps, DropDownProps {
type?: 'primary' | 'ghost' | 'dashed'; // 按鈕類型
disabled?: boolean; // 是否禁用
onClick?: React.MouseEventHandler<any>; // 點擊事件
children?: any; // 子節點
}複製代碼
從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的實現,而後根據日常看代碼的習慣post
從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的組件實現解讀,
最後看完這三篇文章,再倒過來重溫一遍,你將會學到怎麼樣一層層的包裝組件,將一個基礎組件包裝成爲一個高級組件的過程。