Antd Alert 组件
这个组件相对简单,就是一个布局组件
传参
/** 简化后的属性 **/
export interface AlertProps {
type?: 'success' | 'info' | 'warning' | 'error';
message?: React.ReactNode;
description?: React.ReactNode;
onClose?: React.MouseEventHandler<HTMLButtonElement>;
afterClose?: () => void;
showIcon?: boolean;
icon?: React.ReactNode;
}
其实也就是一个用CSSMotion
包裹住的div
组件, 里面渲染了message
. description
, 等
<CSSMotion
visible={!closed}
motionName={`${prefixCls}-motion`}
motionAppear={false}
motionEnter={false}
onLeaveStart={node => ({
maxHeight: node.offsetHeight,
})}
onLeaveEnd={afterClose}
>
{({ className: motionClassName, style: motionStyle }) => (
<div
ref={ref}
className={classNames(alertCls, motionClassName)}
style={{ ...style, ...motionStyle }}
{...props}
>
{isShowIcon ? renderIconNode() : null}
<div className={`${prefixCls}-content`}>
{message ? <div className={`${prefixCls}-message`}>{message}</div> : null}
{description ? <div className={`${prefixCls}-description`}>{description}</div> : null}
</div>
{action ? <div className={`${prefixCls}-action`}>{action}</div> : null}
{renderCloseIcon()}
</div>
)}
</CSSMotion>
值得学习的地方是,renderIconNode
函数
const renderIconNode = () => {
const { icon } = props;
// 这里源码中 iconMapOutlined 是一个map, 里面是一个 { [type: string]: AntdIcon }
const iconType = (description ? iconMapOutlined : iconMapFilled)[type] || null;
if (icon) {
/** 这里replaceElement 其实源码是用 React.cloneElement 去实现的,
* 就是判断icon 是否是element 不是的话就用第二参数, 是的话就克隆element,然后添加其余属性
*/
return replaceElement(icon, <span className={`${prefixCls}-icon`}>{icon}</span>, () => ({
className: classNames(`${prefixCls}-icon`, {
[(icon as any).props.className]: (icon as any).props.className,
}),
}));
}
/** 这里如果是自己写的话, 是用一个div 去包裹着, 而不是像他那样创建一个element, 这里如果换成React.cloneElement是不是更加合适? */
return React.createElement(iconType, { className: `${prefixCls}-icon` });
};