当前位置: 首页 > 工具软件 > Top Drawer > 使用案例 >

Ant-Design组件源码分析——Drawer

东方英豪
2023-12-01

2021SC@SDUSC

源码分析如下

首先导入了相关使用的模块

import * as React from 'react';
import RcDrawer from 'rc-drawer';
import CloseOutlined from '@ant-design/icons/CloseOutlined';
import classNames from 'classnames';
import { ConfigContext, DirectionType } from '../config-provider';
import { tuple } from '../_util/type';
import useForceUpdate from '../_util/hooks/useForceUpdate';

先定义了一个接口,有push和pull方法

type DrawerRef = {
  push(): void;
  pull(): void;
};

 定义了一个抽屉的上下文来用于返回两个对象,一个消费者(使用数据),一个生产者(提供数据)类型为DrawerRef或空(null)

const DrawerContext = React.createContext<DrawerRef | null>(null);

 函数:获取包含的内容

type getContainerFunc = () => HTMLElement;

组件所处的抽屉级别以及多级抽屉情况下所在位置

type ILevelMove = number | [number, number];

抽屉所处的四个位置

onst PlacementTypes = tuple('top', 'right', 'bottom', 'left');
type placementType = typeof PlacementTypes[number];

抽屉大小的两种(默认,可调)

const SizeTypes = tuple('default', 'large');
type sizeType = typeof SizeTypes[number];

添加属性:抽屉拉出来的距离

export interface PushState {
  distance: string | number;
}

抽屉接口

autoFocus:抽屉展开后是否将焦点切换至其 Dom 节点

closable:能否关闭
closeIcon:关闭图标
destroyOnClose:关闭时销毁 Drawer 里的子元素
forceRender:是否预渲染抽屉内元素
getContainer:获取抽屉内元素
maskClosable:能否关闭遮罩
mask:是否显示遮罩
maskStyle:遮罩样式
style:样式
size:抽屉大小
drawerStyle:抽屉样式
headerStyle:头部样式
bodyStyle:body部分样式
title:标题
visible:是否显示
extra:抽屉右上角的额外操作
level:抽屉所处级别
export interface DrawerProps {

  autoFocus?: boolean;
  closable?: boolean;
  closeIcon?: React.ReactNode;
  destroyOnClose?: boolean;
  forceRender?: boolean;
  getContainer?: string | HTMLElement | getContainerFunc | false;
  maskClosable?: boolean;
  mask?: boolean;
  maskStyle?: React.CSSProperties;
  style?: React.CSSProperties;
  size?: sizeType;
  /** Wrapper dom node style of header and body */
  drawerStyle?: React.CSSProperties;
  headerStyle?: React.CSSProperties;
  bodyStyle?: React.CSSProperties;
  contentWrapperStyle?: React.CSSProperties;
  title?: React.ReactNode;
  visible?: boolean;
  width?: number | string;
  height?: number | string;
  zIndex?: number;
  prefixCls?: string;
  push?: boolean | PushState;
  placement?: placementType;
  onClose?: (e: EventType) => void;
  afterVisibleChange?: (visible: boolean) => void;
  className?: string;
  handler?: React.ReactNode;
  keyboard?: boolean;
  extra?: React.ReactNode;
  footer?: React.ReactNode;
  footerStyle?: React.CSSProperties;
  level?: string | string[] | null | undefined;
  levelMove?:
    | ILevelMove
    | ((e: { target: HTMLElement; open: boolean }) => ILevelMove);
}

默认抽出距离为180

const defaultPushState: PushState = { distance: 180 };

强制重新渲染

const forceUpdate = useForceUpdate();

父抽屉

const parentDrawer = React.useContext(DrawerContext);

关闭清除抽屉元素

const destroyClose = React.useRef<boolean>(false);

设定推拉函数(关闭打开)

const operations = React.useMemo(
      () => ({
        push() {
          if (push) {
            setPush(true);
          }
        },
        pull() {
          if (push) {
            setPush(false);
          }
        },
      }),
      [push],
    );

函数:如果本抽屉可见或父抽屉存在时,关闭该抽屉并将父抽屉拉出

React.useEffect(() => {
      // fix: delete drawer in child and re-render, no push started.
      // <Drawer>{show && <Drawer />}</Drawer>
      if (visible && parentDrawer) {
        parentDrawer.push();
      }

      return () => {
        if (parentDrawer) {
          parentDrawer.pull();
          // parentDrawer = null;
        }
      };
    }, []);

获取样式

const getOffsetStyle = () => {
      // https://github.com/ant-design/ant-design/issues/24287
      if (!visible && !mask) {
        return {};
      }
      const offsetStyle: any = {};
      if (placement === 'left' || placement === 'right') {
        const defaultWidth = size === 'large' ? 736 : 378;
        offsetStyle.width = typeof width === 'undefined' ? defaultWidth : width;
      } else {
        const defaultHeight = size === 'large' ? 736 : 378;
        offsetStyle.height = typeof height === 'undefined' ? defaultHeight : height;
      }
      return offsetStyle;
    };

 类似资料: