使用 React 实现全局 Message 组件
在前端开发中常用的组件之一就是进行全局通知,一般的组件库都提供了这些功能:
全局提示 Message - Ant Design (gitee.io)
Message 全局提示 | TDesign (tencent.com)
这里将不使用第三方库,自己动手实现一个简单的全局消息组件
所有的代码都在一个
tsx
文件中
全局消息的组成
- 一个可以全局调用的对象
- 一个消息列表组件
- 一个消息组件
定义消息的类型
消息一般分为 成功、信息、警告、错误 四种,这里使用枚举进行定义
// 消息的类型枚举
enum MessageType {
Success = "success",
Error = "error",
Warning = "warning",
Info = "info"
}
定义全局消息的对象的类型
也就是分别对应上述四种类型的方法
// 消息对象类型
type Message = {
success: (message: string) => void
error: (message: string) => void
warning: (message: string) => void
info: (message: string) => void
}
定义消息组件
onRemove
方法用来移除当前组件,移除交给上级组件完成
// 消息组件参数
type MessageProps = {
id: string
type: MessageType
content: string
onRemove?: (id: string) => void
}
// 消息组件
const MessageItem: React.FC<MessageProps> = (props) => {
setTimeout(() => {
props.onRemove?.(props.id);
}, 2000);
return (
<div className={`message-item ${props.type}`}>{props.content}</div>
);
};
定义消息列表组件
这里通过每次需要页面更新时修改 flagId
来实现刷新的效果
// 消息对象
const message: Partial<Message> = {};
// 标识消息的ID
let incrementId = 0;
// 消息列表对象
const messageList: { [key: string]: MessageProps } = {};
// 消息列表组件
const MessageList = () => {
const [flagId, setFlagId] = useState(0);
const removeById = (id: string) => {
delete messageList[id];
setFlagId(flagId + 1);
};
const _message = (type: MessageType, content: string) => {
const id = `${++incrementId}`;
messageList[id] = {
id: id,
type: type,
content: content,
};
setFlagId(flagId + 1);
};
message.success = (content: string) => {
_message(MessageType.Success, content);
};
message.error = (content: string) => {
_message(MessageType.Error, content);
};
message.warning = (content: string) => {
_message(MessageType.Warning, content);
};
message.info = (content: string) => {
_message(MessageType.Info, content);
};
return (
<div className="message-list">
{Object.keys(messageList).map(key => {
const item = messageList[key];
return <MessageItem key={item.id} id={item.id} type={item.type} content={item.content}
onRemove={removeById}></MessageItem>;
})}
</div>
);
};
加载时自动挂载全局消息的模态框
// 在加载 JS 时在页面上挂载消息 model
const messageModelContainer = document.createElement("div");
messageModelContainer.className = "message-model-container";
document.body.appendChild(messageModelContainer);
ReactDOM.createRoot(messageModelContainer as HTMLElement).render(
<MessageList></MessageList>
);
最后导出 message 对象
export default message as Message;
对应的 scss 文件
.message-model-container {
z-index: 1000;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
display: flex;
justify-content: center;
.message-list {
width: 350px;
position: relative;
.message-item {
position: absolute;
top: -64px;
width: 100%;
box-sizing: border-box;
height: 48px;
line-height: 48px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
box-shadow: rgba(0, 0, 0, 0.2) 0 0 8px;
border-radius: 4px;
padding: 0 16px;
margin-top: 12px;
background-color: white;
animation: message-item-animation 2s;
&.success {
border-left: solid 4px var(--success-color);
}
&.error {
border-left: solid 4px var(--error-color);
}
&.warning {
border-left: solid 4px var(--warning-color);
}
&.info {
border-left: solid 4px var(--info-color);
}
@keyframes message-item-animation {
0% {
top: -64px;
}
20% {
top: 0;
}
80% {
top: 0;
}
100% {
top: -64px;
}
}
}
}
}