antd有个Notification组件用于全局通知提醒, 现在用react实现一个相同的组件。
image.png
思考这个组件:
- 全局提示 ,即在任何地方都可以通过方法调用
- 如何将组件渲染到页面上
定义方法名称为toast,可以知道在使用时,只要调用toast() 就会在页面上出现提示,几秒后提示消失,也可以手动关闭
该类组件一般会有一些像success,error ,warning的分类,所以调用的形式是toast.success('提示文案')
一、第一步:dom实现
const dispatchToast = (toast, type) => {
let item = { toast, type }
if (containerDomNode) {
//当containerDomNode存在时,不重新createElement
globalControl.add(item)
} else {
containerDomNode = document.createElement('div')
document.body.appendChild(containerDomNode)
//ToastContainer是提示组件
ReactDOM.render(<ToastContainer initToast={item} />, containerDomNode)
}
}
export default {
success: v => dispatchToast(v, 'success'),
error: v => dispatchToast(v, 'error'),
warning: v => dispatchToast(v, 'warning')
}
globalControl是一个全局的控制器, 用于控制组件的数量
containerDomNode是一个全局变量,是用于放置组件的面板
第二步:实现ToastContainer
const ToastContainer = ({ initToast }) => {
const [queue] = useQueue()
useEffect(() => {
if (initToast) {
globalControl.add(initToast)
}
}, [])
return (
<div className={styles.container}>
{queue.map(el => (
<p
className={`${styles.item} ${styles[el.type]}`}
key={el._tid}
onClick={() => globalControl.rm(el._tid)}
>
{el.content}
</p>
))}
</div>
)
}
queue就是toast的数量
第三步:自定义useQueue勾子
// toast标识符计数器
let tid = 0
let globalControl = {}
let containerDomNode = undefined
// 默认配置
const defaultOption = {
duration: 3000,
content: 'this is default content!'
}
const useQueue = () => {
const [queue, setQueue] = useState([])
const add = (item = {}) => {
const _tid = getName()
item = Object.assign({ _tid }, defaultOption, item)
setQueue(v => [...v, item])
setTimeout(() => rm(item._tid), item.duration)
}
const rm = tid => {
setQueue(v => v.filter(el => el._tid !== tid))
}
const getName = () => `__toast_id_${++tid}`
const control = {
add,
rm
}
globalControl = control
return [queue]
}
网友评论