「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
Message组件通常用于全局展示操作反馈信息。在页面上我们会有一个操作按钮,用户点击某项操作后,会进行相应的逻辑处理,基于用户操作成功、失败的提示信息来告知用户的操作情况。并且该消息提示一般位于页面顶部,不会影响用户的其他操作。
在antd-design中提供了五种样式的消息提示,包括成功、失败、loading等提示,它还可以设置提示时长、更新某条消息等功能。他又提供了那些属性让我们来操作呢?可以见官方文档API,然后我们来简单分析一下它的基础功能,肯定分析的不会那么完善,先看看他所需要的属性吧。
export interface ArgsProps {
content: React.ReactNode; // 消息提示的内容
duration?: number; // 显示时间
type: NoticeType; // 那种消息类型
onClose?: () => void; // 关闭时回调
icon?: React.ReactNode; // 消息前面的icon
key?: string | number; // 消息唯一的key,用来标识、销毁、更新
style?: React.CSSProperties;
className?: string;
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void; // 点击消息
}
在antd-design官网例子中,可以知道,我们是调用message.success(config)这种方式来进行消息提示的,所以Message消息提示是导出了一个message的对象,提供了一个属性方法来实现的,当然它还导出了其他的,如getInstance方法,来获取消息的实例。
const api: any = {
open: notice, // 真正弹出消息的方法
config: setMessageConfig,
destroy(messageKey?: React.Key) { },
};
// 在 api 对象上绑定多个方法,内部还是用 open => notice 方法实现的
(['success', 'info', 'warning', 'error', 'loading'] as NoticeType[]).forEach(type =>
attachTypeApi(api, type),
);
api.warn = api.warning;
api.useMessage = createUseMessage(getRCNotificationInstance, getRCNoticeProps);
interface MessageApi {};
export default api as MessageApi;
我们先定义了一个对象api,给它定义了不同的属性,然后对于类似属性'success', 'info', 'warning', 'error', 'loading'就直接调用工厂函数attachTypeApi来对生成的函数绑定在api对象上。然后进行导出,在外部调用静态方法就可以弹出提示了。
// 往 api 对象上绑对应的方法
export function attachTypeApi(originalApi: MessageApi, type: NoticeType) {
// api['success]...本质上还是调用open方法(notcie方法)
originalApi[type] = (
content: JointContent,
duration?: ConfigDuration,
onClose?: ConfigOnClose,
) => {
if (isArgsProps(content)) {
return originalApi.open({ ...content, type });
}
// 没传 duration 时,第二项就是 回调函数
if (typeof duration === 'function') {
onClose = duration;
duration = undefined;
}
return originalApi.open({ content, duration, type, onClose });
};
}
以message.success(config)为例,调用该方法后,它是一个怎样的流程呢?
- 从上面看到调用
success方法,本质上就是调用notcie方法
// 弹出·message 提示的函数
function notice(args: ArgsProps): MessageType {
const target = args.key || getKeyThenIncreaseKey(); // 没有传入key,则采用默认的key,从 1 开始 ++
// 关闭的
const closePromise = new Promise(resolve => {
const callback = () => {
if (typeof args.onClose === 'function') {
args.onClose();
}
return resolve(true);
};
getRCNotificationInstance(args, ({ prefixCls, iconPrefixCls, instance }) => {
// rc-notification 返回的·实例 instance.notice
instance.notice(
getRCNoticeProps({ ...args, key: target, onClose: callback }, prefixCls, iconPrefixCls),
);
});
});
const result: any = () => {
// 移除
if (messageInstance) {
messageInstance.removeNotice(target);
}
};
result.then = (filled: ThenableArgument, rejected: ThenableArgument) =>
closePromise.then(filled, rejected);
result.promise = closePromise;
return result;
}
在getRCNotificationInstance方法中主要就是根据传入的props来调用RCNotification.newInstance()方法,RCNotification其实是用的rc-notification模块,大家感兴趣可以搜一下看看他的使用方法。RCNotification.newInstance(instanceConfig,(instance: any) => {})方法会在回调函数中传入消息实例instance,然后将该实例传入我们定义的回调函数中,接收到实例后调用instance.notice()方法来进行提示,它需要的参数是经过getRCNoticeProps()方法处理的,该方法主要就是生成我们的props来传入到instance.notice()方法中。
function getRCNotificationInstance(
args: ArgsProps,
callback: (info: {
prefixCls: string;
rootPrefixCls: string;
iconPrefixCls: string;
instance: RCNotificationInstance;
}) => void,
) {
// ...
if (messageInstance) {
callback({ prefixCls, rootPrefixCls, iconPrefixCls, instance: messageInstance });
return;
}
// 初次实例化
const instanceConfig = {
prefixCls,
transitionName: hasTransitionName ? transitionName : `${rootPrefixCls}-${transitionName}`,
style: { top: defaultTop }, // 覆盖原来的样式
getContainer: getContainer || getContextPopupContainer,
maxCount,
};
RCNotification.newInstance(instanceConfig, (instance: any) => {
if (messageInstance) {
callback({ prefixCls, rootPrefixCls, iconPrefixCls, instance: messageInstance });
return;
}
messageInstance = instance;
callback({ prefixCls, rootPrefixCls, iconPrefixCls, instance });
});
}
那我们如何关闭一个消息呢,除了默认关闭外,我们还可以调用message.destroy(key?:string)方法来关闭它。
const api: any = {
// ...
destroy(messageKey?: React.Key) {
// messageInstance 是messgae组件的实例,实际上是rc-notification模块返回的instance实例
// removeNotice、destroy都是由instance实例提供的
if (messageInstance) {
// 有key就只移除他自己,掉自身的 方法removeNotice
if (messageKey) {
const { removeNotice } = messageInstance;
removeNotice(messageKey);
} else {
// 全局销毁
const { destroy } = messageInstance;
destroy();
messageInstance = null;
}
}
},
};
至此,一个基础的消息提示就封装好了,主要还是依赖了rc-notification模块,大家感兴趣可以看看。
相关文档: