1.何时使用
- 当需要展示标题、段落、列表内容时使用,如文章/博客/日志的文本样式。
- 当需要一列基于文本的基础操作时,如拷贝/省略/可编辑。
2.代码演示
ant-design.antgroup.com/components/…
3.源码学习
3.1 Typography
const Typography = React.forwardRef<
HTMLElement,
InternalTypographyProps<keyof JSX.IntrinsicElements>
>((props, ref) => {
const {
prefixCls: customizePrefixCls,
component: Component = 'article', //属性是HTMLElement的要定个首字母大写
className,
rootClassName,
setContentRef,
children,
direction: typographyDirection,
style,
...restProps
} = props;
return wrapCSSVar(
// @ts-expect-error: Expression produces a union type that is too complex to represent.
<Component className={componentClassName} style={mergedStyle} ref={mergedRef} {...restProps}>
{children}
</Component>,
);
3.2 Title
const Title = React.forwardRef<HTMLElement, TitleProps>((props, ref) => {
//属性要给予默认值
const { level = 1, ...restProps } = props;
let component: keyof JSX.IntrinsicElements;
...
//严格判断输入的属性是否合法
if (TITLE_ELE_LIST.includes(level)) {
component = `h${level}`;
} else {
component = 'h1';
}
return <Base ref={ref} {...restProps} component={component} />;
});
3.3 Text
const Text: React.ForwardRefRenderFunction<HTMLSpanElement, TextProps> = (
{ ellipsis, ...restProps },
ref,
) => {
const mergedEllipsis = React.useMemo(() => {
if (ellipsis && typeof ellipsis === 'object') {
return omit(ellipsis as EllipsisConfig, ['expandable', 'rows']);
}
return ellipsis;
}, [ellipsis]);
...
return <Base ref={ref} {...restProps} ellipsis={mergedEllipsis} component="span" />;
};
3.4 Paragraph
const Paragraph = React.forwardRef<HTMLElement, ParagraphProps>((props, ref) => (
<Base ref={ref} {...props} component="div" />
));
3.5 Link
const Link = React.forwardRef<HTMLElement, LinkProps>(({ ellipsis, rel, ...restProps }, ref) => {
return <Base {...mergedProps} ref={ref} ellipsis={!!ellipsis} component="a" />;
});
3.6 Editable组件
const inComposition = React.useRef(false);
const lastKeyCode = React.useRef<number>();
const [current, setCurrent] = React.useState(value);
React.useEffect(() => {
setCurrent(value);
}, [value]);
const onChange: React.ChangeEventHandler<HTMLTextAreaElement> = ({ target }) => {
setCurrent(target.value.replace(/[\n\r]/g, ''));
};
const onCompositionStart = () => {
inComposition.current = true; //改变 `ref.current` 属性时,React 不会重新渲染组件。React 不知道它何时会发生改变,因为 ref 是一个普通的 JavaScript 对象
};
const onCompositionEnd = () => {
inComposition.current = false;
};
const onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = ({ keyCode }) => {
// We don't record keyCode when IME is using
if (inComposition.current) return;
lastKeyCode.current = keyCode; //存值,直到组件销毁才丢弃
};
const onKeyUp: React.KeyboardEventHandler<HTMLTextAreaElement> = ({
keyCode,
ctrlKey,
altKey,
metaKey,
shiftKey,
}) => {
// Check if it's a real key
if (
lastKeyCode.current === keyCode &&
!inComposition.current &&
!ctrlKey &&
!altKey &&
!metaKey &&
!shiftKey
) {
if (keyCode === KeyCode.ENTER) {
confirmChange();
onEnd?.();
} else if (keyCode === KeyCode.ESC) {
onCancel();
}
}
};
const confirmChange = () => {
onSave(current.trim());
};
const onBlur: React.FocusEventHandler<HTMLTextAreaElement> = () => {
confirmChange();
};
return wrapCSSVar(
<div className={textAreaClassName} style={style}>
<TextArea
ref={ref}
maxLength={maxLength}
value={current}
onChange={onChange}
onKeyDown={onKeyDown}
onKeyUp={onKeyUp}
onCompositionStart={onCompositionStart}
onCompositionEnd={onCompositionEnd}
onBlur={onBlur}
aria-label={ariaLabel}
rows={1}
autoSize={autoSize}
/>
{enterIcon !== null
? cloneElement(enterIcon, { className: `${prefixCls}-edit-content-confirm` })
: null}
</div>,
);
3.7 定时器
// Simple module exposing `copy` function that will try to use [execCommand] with fallback to IE-specific `clipboardData` interface and finally, resort to usual `prompt` with proper text content and message.
// https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
import copy from 'copy-to-clipboard';
const copyIdRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
const cleanCopyId = () => {
if (copyIdRef.current) {
clearTimeout(copyIdRef.current);
}
};
const onCopyClick = (e?: React.MouseEvent<HTMLDivElement>) => {
e?.preventDefault(); //阻止默认事件
e?.stopPropagation(); //阻止冒泡
copy(copyConfig.text || String(children) || '', copyOptions);
setCopied(true);
// Trigger tips update
cleanCopyId(); //每次点击都要先清除掉之前的定时器会导致内存溢出,同时可以防抖
copyIdRef.current = setTimeout(() => {
setCopied(false);
}, 3000);
copyConfig.onCopy?.(e);
};
React.useEffect(() => cleanCopyId, []); 返回值会在unmount时调用,清除定时器
3.8 aria-hidden 属性
developer.mozilla.org/zh-CN/docs/…
aria-hidden是一个用于辅助功能(Accessibility)的HTML属性,用于指示元素是否对辅助技术(如屏幕阅读器)隐藏。
辅助功能是一种设计和开发网页的方法,旨在使网页对于残障人士和使用辅助技术的人更易访问。aria-hidden属性可以应用于任何HTML元素,用于指示该元素是否应该在辅助技术中隐藏或忽略。