前言
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组件。
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>
);