antd源码解读(8)- Dropdown

antd源码解读(8)- Dropdown下拉菜单组件是一个可以将页面上比较冗杂的操作收纳在一个点,以便节省页面空间,达到整洁美观的目的。 Antd的下拉菜单组件中有一个点,就是他的内部元素必须是Antd的Menu组件,感觉有点捆绑的意思。 所以这里只是对其参数做了一些封装,比较简单。 这个组件是一个带按钮的下拉菜单组…

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

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注