Ant-design 源码分析之数据展示(一)Avatar
2021SC@SDUSC
一、组件结构
1、ant代码结构
2、rc-ant代码结构
2.1、rc-util代码结构
2.2、rc-resize-observer代码结构
3、组件结构
ant中Avatar的index.tsx中引入了avatar和group
avatar中引用rc-resize-obsever做API。
二、antd组件调用关系
1、avatar.tsx
导入相应模块以及相应的ICON图标
import * as React from 'react';
import classNames from 'classnames';
import ResizeObserver from 'rc-resize-observer';
import { composeRef } from 'rc-util/lib/ref';
import { ConfigContext } from '../config-provider';
import devWarning from '../_util/devWarning';
import { Breakpoint, responsiveArray } from '../_util/responsiveObserve';
import useBreakpoint from '../grid/hooks/useBreakpoint';
import SizeContext, { AvatarSize } from './SizeContext';
创建了AvatarProps接口。
shape:指定头像的形状,有circle、square两种类型。
size:设置头像大小,有large、small、default、number( { xs: number, sm: number, …})类型。
gap:设置字符距离左右两侧边界单位像素,为number类型。
src:图片类头像的资源地址或者图片元素。为string或ReactNode类型。
srcSet:设置图片类头像响应式资源地址。是string类型。
darggable:设置图片是否允许拖动,为boolean类型。
icon:设置头像,为ReactNode类型。
style:使用css主题,为React.CSSProperties类型。
alt:设置图像无法显示时的替代文本。为string类型。
crossOrigin:CORS 属性设置。‘anonymous’ | ‘use-credentials’ | ‘’。
OnError:图片加载失败的事件,返回 false 会关闭组件默认的 fallback 行为。() => boolean。
export interface AvatarProps {
/** Shape of avatar, options: `circle`, `square` */
shape?: 'circle' | 'square';
/*
* Size of avatar, options: `large`, `small`, `default`
* or a custom number size
* */
size?: AvatarSize;
gap?: number;
/** Src of image avatar */
src?: React.ReactNode;
/** Srcset of image avatar */
srcSet?: string;
draggable?: boolean;
/** Icon to be used in avatar */
icon?: React.ReactNode;
style?: React.CSSProperties;
prefixCls?: string;
className?: string;
children?: React.ReactNode;
alt?: string;
crossOrigin?: '' | 'anonymous' | 'use-credentials';
/* callback when img load error */
/* return false to prevent Avatar show default fallback behavior, then you can do fallback by your self */
onError?: () => boolean;
}
setScaleParam:
当有子组件时,根据gap设定子组件大小。
const setScaleParam = () => {
if (!avatarChildrenRef.current || !avatarNodeRef.current) {
return;
}
const childrenWidth = avatarChildrenRef.current.offsetWidth; // offsetWidth avoid affecting be transform scale
const nodeWidth = avatarNodeRef.current.offsetWidth;
// denominator is 0 is no meaning
if (childrenWidth !== 0 && nodeWidth !== 0) {
const { gap = 4 } = props;
if (gap * 2 < nodeWidth) {
setScale(nodeWidth - gap * 2 < childrenWidth ? (nodeWidth - gap * 2) / childrenWidth : 1);
}
}
};
handleImgLoadError:
判断图片是否加载失败。根据OnError()判断。
const handleImgLoadError = () => {
const { onError } = props;
const errorFlag = onError ? onError() : undefined;
if (errorFlag !== false) {
setIsImgExist(false);
}
};
设置各项属性。
const {
prefixCls: customizePrefixCls,
shape,
size: customSize,
src,
srcSet,
icon,
className,
alt,
draggable,
children,
crossOrigin,
...others
} = props;
const responsiveSizeStyle: React.CSSProperties = React.useMemo(() => {
if (typeof size !== 'object') {
return {};
}
const currentBreakpoint: Breakpoint = responsiveArray.find(screen => screens[screen])!;
const currentSize = size[currentBreakpoint];
return currentSize
? {
width: currentSize,
height: currentSize,
lineHeight: `${currentSize}px`,
fontSize: icon ? currentSize / 2 : 18,
}
: {};
}, [screens, size]);
2、group.tsx
导入相应模块以及相应的ICON图标
import * as React from 'react';
import classNames from 'classnames';
import toArray from 'rc-util/lib/Children/toArray';
import { cloneElement } from '../_util/reactNode';
import { ConfigContext } from '../config-provider';
import Avatar from './avatar';
import Popover from '../popover';
import { AvatarSize, SizeContextProvider } from './SizeContext';
创建了GroupProps接口。
export interface GroupProps {
className?: string;
children?: React.ReactNode;
style?: React.CSSProperties;
prefixCls?: string;
maxCount?: number;
maxStyle?: React.CSSProperties;
maxPopoverPlacement?: 'top' | 'bottom';
/*
* Size of avatar, options: `large`, `small`, `default`
* or a custom number size
* */
size?: AvatarSize;
}
prefixCls:改变jsx文件里面的dom节点的className名称,string类型。
maxCount:显示的最大头像个数,number类型。
maxStyle:多余头像样式,CSSProperties类型。
maxPopoverPlacement:多余头像气泡弹出位置,top | bottom。
size:设置头像的大小,number | large | small | default | { xs: number, sm: number, …}类型。
通过接口实现了Group
const Group: React.FC<GroupProps> = props => {
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const { prefixCls: customizePrefixCls, className = '', maxCount, maxStyle, size } = props;
const prefixCls = getPrefixCls('avatar-group', customizePrefixCls);
const cls = classNames(
prefixCls,
{
[`${prefixCls}-rtl`]: direction === 'rtl',
},
className,
);
const { children, maxPopoverPlacement = 'top' } = props;
const childrenWithProps = toArray(children).map((child, index) =>
cloneElement(child, {
key: `avatar-key-${index}`,
}),
);
const numOfChildren = childrenWithProps.length;
if (maxCount && maxCount < numOfChildren) {
const childrenShow = childrenWithProps.slice(0, maxCount);
const childrenHidden = childrenWithProps.slice(maxCount, numOfChildren);
childrenShow.push(
<Popover
key="avatar-popover-key"
content={childrenHidden}
trigger="hover"
placement={maxPopoverPlacement}
overlayClassName={`${prefixCls}-popover`}
>
<Avatar style={maxStyle}>{`+${numOfChildren - maxCount}`}</Avatar>
</Popover>,
);
return (
<SizeContextProvider size={size}>
<div className={cls} style={props.style}>
{childrenShow}
</div>
</SizeContextProvider>
);
}
return (
<SizeContextProvider size={size}>
<div className={cls} style={props.style}>
{childrenWithProps}
</div>
</SizeContextProvider>
);
};
三、rc-antd组件调用关系
1、Rc-resize-observer
Rc-resize-observer:
生命周期方法:
componentDidMount()
请求数据,一般用在进入页面后,数据初始化。在第一次渲染后调用,只在客户端。之后 组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你 想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval
或者发送AJAX请求等操作(防止异步操作阻塞UI)。
componentDidUpdate()
在组件完成更新后立即调用。在初始化时不会被调用。
一般的情况是管理第三个的UI组件,以及和本地UI元素交互。
componentWillUnmount()
在渲染前调用,在客户端也在服务端。
onComponentUpdated()
当禁用或元素改变时,取消注册,调用onResize()方法,传递元素element。
onResize()
会在窗口或框架被调整大小时发生。动态调整窗口大小。
destroyObserver()
关闭观察者。
render()
渲染。
2、Rc-util
待更新。