antd typography源码解析

1,132 阅读1分钟

前言

typography是排版组件,包括Title, Text等多个小组件。
基本思路是传递不同的属性值给Base组件。小组件的props基本属性定义在Typography.tsx中

export interface TypographyProps {
  id?: string;
  prefixCls?: string;
  className?: string;
  style?: React.CSSProperties;
  children?: React.ReactNode;
  ['aria-label']?: string;
}

然后通过rc-util/lib/omit, 用浅拷贝的方式挑选出需要的属性。

源码详解

详细看下Base组件做了什么。

class Base extends React.Component<InternalBlockProps, BaseState> {
    render() {
        // getEditable根据props是否有editable返回一个对象{editing: xx, ...editable配置}
        const { editing } = this.getEditable();
        // 渲染可编辑的组件
        if (editing) {
          return this.renderEditInput();
        }
        // 渲染不可编辑的组件
        return this.renderContent();
    }
}

渲染未在编辑的组件

先来看renderContent: 整理好属性后,最终调用的是Typography组件。

return (
    <LocaleReceiver componentName="xxx">
        {({edit, copy, copied, expand}: Locale) => {
            // xxx
            return (
                <ResizeObserver>
                    <Typography xxx>
                        {textNode}
                        // 如果有省略内容展开、可编辑、可复制的,渲染这部分内容
                        {this.renderOperations()}
                    </Typography>
                </ResizeObserver>
            )
        }}
    </LocaleReceiver>
)

先看上面的LocaleReceiver,作用主要是为了实现组件的国际化。相当于此处获取到配置后传给了Base组件。

image.png

ResizeObserver使用的rc-resize-observer,暂不分析。

接下来看Typography组件,比较简单,单纯将属性添加到componentName指定的标签上

componentName对应关系
Title--->hx(默认h1)
Text--->span
Paragraph--->div

  return (
    // ConfigConsumer会将上下文的数据作为参数传入renderProps渲染的函数之内,
    // 所以这个函数内才可以访问上下文的数据
    <ConfigConsumer>
      {({ getPrefixCls, direction }: ConfigConsumerProps) => {
        const Component = component as any;
        const prefixCls = getPrefixCls('typography', customizePrefixCls);
        const componentClassName = classNames(
          prefixCls,
          {
            [`${prefixCls}-rtl`]: direction === 'rtl',
          },
          className,
        );
        return (
          <Component
            className={componentClassName}
            aria-label={ariaLabel}
            ref={mergedRef}
            {...restProps}
          >
            {children}
          </Component>
        );
      }}
    </ConfigConsumer>
  );

渲染正在编辑的组件

renderEditInput是将属性值传给Editable组件进行渲染的

return (
  <Editable />
)

Editable的代码很简单

return (
    <div className={textAreaClassName} style={style}>
      <TextArea
        ref={ref as any}
        maxLength={maxLength}
        value={current}
        onChange={onChange}
        // 输入中文的过程中不记录keycode, 输入完毕再记录
        onKeyDown={onKeyDown}
        // 对enter和esc按键事件做处理
        onKeyUp={onKeyUp}
        // onCompositionStart和onCompositionEnd是监听中文字符开始输入和输入完毕的事件
        onCompositionStart={onCompositionStart}
        onCompositionEnd={onCompositionEnd}
        // 失去焦点保存数据
        onBlur={onBlur}
        aria-label={ariaLabel}
        autoSize={autoSize}
      />
      <EnterOutlined className={`${prefixCls}-edit-content-confirm`} />
    </div>
  );