手动实现一个react的message组件
组件目录如下:
- Message入口文件
// index.tsx
import { useState,useEffect } from 'react';
import * as ReactDOM from 'react-dom';
import Msg from './Msg';
import { MessageApi,List } from './config';
import './index.less';
let add: (L: List) => void;
export const MessageContainer = () => {
const [lists ,setList] = useState<List[]>([]);
const remove = (L:List) => {
const { key } = L;
setList((pre:List[]) => ( pre.filter((each:List) => key !== each.key) ))
}
add = (option:List) => {
setList((pre:List[])=>{
const obj = [...pre,option ];
setTimeout(() => {
remove(option)
}, 3000)
return obj
})
// 最好不用下面这个写法,当同时调用两个message时候,只会显示最后调用那次
// const obj = [...lists,option ];
// setList(obj);
// setTimeout(() => {
// remove(option)
// }, timeout)
}
useEffect(() => {
if (lists.length > 10) {
lists.shift();
}
}, [lists])
return (
<>
{
lists.map(({ text, key, type }) => (
<Msg key={key} type={type} text={text} />
))
}
</>
)
}
// 获取唯一id
const getId = () => {
return (Math.random() * 1000).toFixed()
}
// 暴露的message-API
const $message: MessageApi = {
info: (text) => {
add({
text,
key: getId(),
type: 'info'
})
},
success: (text) => {
add({
text,
key: getId(),
type: 'success'
})
},
warning: (text) => {
add({
text,
key: getId(),
type: 'warning'
})
},
error: (text) => {
add({
text,
key: getId(),
type: 'error'
})
}
}
export default $message;
// 挂载容器到页面
const createMessage = () => {
let el = document.getElementById('#message-wrap');
// 这一步是必要的的,因为在执行到这里的时候,页面还没有挂载,所以获取不到el节点
if (!el) {
el = document.createElement('div')
el.className = 'message-wrap'
el.id = 'message-wrap'
document.body.append(el)
}
ReactDOM.render( <MessageContainer />, el);
}
createMessage();
- Message样式文件
//index.less
.message-wrap{
position: fixed;
left: 50%;
top: 60px;
transform: translate(-50%);
z-index: 1000;
.message{
height: 34px;
min-width: 180px;
padding: 0px 10px;
font-size: 12px;
margin-top: 20px;
display: flex;
align-items: center;
border-radius: 4px;
box-shadow: 0 0 8px #ddd;
border: 1px solid #eee;
.icon {
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 6px;
}
}
.info {
color: #5a98e9;
>.icon{
background: #5a98e9;
}
}
.error {
color: #ff4d4f;
>.icon{
background: #ff4d4f;
}
}
.warning {
color: #faad14;
>.icon{
background: #faad14;
}
}
.success {
color: #52c41a;
>.icon{
background: #52c41a;
}
}
}
- Message消息模板
// Msg.tsx
const Msg = ({type, text }:{ type:string,text: string }) => {
return (
<div className={`message ${type}`}>
<span className='icon' />
<span>{text}</span>
</div>
);
};
export default Msg;
- ts校验的配置文件
// config.ts
export interface MessageApi {
info: (text: string) => void;
success: (text: string) => void;
warning: (text: string) => void;
error: (text: string) => void;
}
export interface List {
text: string;
key: string;
type: 'info' | 'success' | 'error' | 'warning';
}
- 使用react版本的message
import $message from '../component/index';
$message.success('我是一条成功的自定义消息')
效果: