写前:空余时间,看 antd 发现此组件有趣,便模仿写来玩,不喜勿喷,望提建议。
先上效果图:
Message.js
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import "./style.less";
const div = document.createElement("div");
document.body.appendChild(div);
function notice(args) {
return ReactDOM.render(<Message {...args} />, div);
}
let timer;
function Message(props) {
const [msgs, setMsgs] = useState([]);
const { content, type } = props;
const iconObj = {
info: "mf-icon-information",
success: " mf-icon-selected2",
warn: "mf-icon-Prompt",
error: " mf-icon-remove",
};
useEffect(() => {
setMsgs([...msgs, props]);
}, [props]);
useEffect(() => {
if (msgs.length) {
let msgscopy = JSON.parse(JSON.stringify(msgs));
// setInterval 写法
clearInterval(timer);
timer = setInterval(
(setMsgs) => {
msgscopy.shift();
setMsgs(JSON.parse(JSON.stringify(msgscopy)));
if (!msgscopy.length) {
clearInterval(timer);
}
},
props.duration * 1000,
setMsgs
);
// clearTimeout 写法
// clearTimeout(timer);
// let fn = (setMsgs) => {
// msgscopy.shift();
// setMsgs(JSON.parse(JSON.stringify(msgscopy)));
// if (msgscopy.length) {
// timer = setTimeout(fn, props.duration * 1000, setMsgs);
// }
// };
// timer = setTimeout(fn, props.duration * 1000, setMsgs);
}
}, [msgs]);
return (
<div className="message">
{msgs.map((item, index) => {
return (
<div className="message-content" key={index}>
<i className={`${iconObj[type]} message-content-icon` }></i>
<span className="message-content-text">{content}</span>
</div>
);
})}
</div>
);
}
let api = {};
["info", "success", "warn", "error"].forEach((type) => {
api[type] = (content, duration = 3) => {
return notice({ content, duration, type });
};
});
export default api;
// 目前该组件只包含了 "info", "success", "warn", "error" 这几种,其他的按需自行添加即可;
// `duration` 为时长;
// 具体可参照 ant design 完善;
style.less
.message {
position: fixed;
top: 85px;
left: 50%;
transform: translate(-50%, 0);
z-index: 1000;
&-content {
max-width: 800px;
background: rgba(0, 0, 0, 0.6);
padding: 13px 64px;
border-radius: 6px;
margin-top: 8px;
font-size: 14px;
font-family: Avenir-Medium, Avenir;
font-weight: 500;
color: rgba(255, 255, 255, 1);
line-height: 22px;
display: flex;
align-items: flex-start;
&-icon{
margin-right: 8px;
font-size: 20px;
}
}
}
- 用这种形式
ReactDOM.render(<Message {...args} />, div);来连接 ReactElement 和 DOMElement ;- 通过调用
notice()方法来动态渲染内容;msgs数组来显示多条和取消显示message组件;
Index.js
import React from "react";
import message from "./Message";
function Index (){
const handleClick = ()=>{
message.warn('我是全局提示组件');
// message.info('我是全局提示组件'); 其他提示类型都按照此方式即可。
// message.info('我是全局提示组件',4); 第二个参数为自定义时长。
}
return (
<div>
<button onClick={handleClick}>click me</button>
</div>
)
}
export default Index;