模仿antd
的message
组件封装的简约版Toast
组件.
组件文件(.jsx)
Toast/index.jsx
/\*\*
\* @nameToast
\* @authordarcrand
\* @date 2020-01-20
\* @desc 提示信息
\*/
importReact, { Component } from'react'
importReactDOMfrom'react-dom'
import { CSSTransition, TransitionGroup } from'react-transition-group'
import'./styles.less'
importicoInfofrom'@/assets/component-toast/toast-info.svg'
importicoSuccessfrom'@/assets/component-toast/toast-success.svg'
importicoWarningfrom'@/assets/component-toast/toast-warning.svg'
importicoErrorfrom'@/assets/component-toast/toast-error.svg'
// 切换动画持续时间(ms), 需要和'less'中的'@time'保持一致
constANIMATION\_DURATION\_TIME\=250
// api(提示)类型
constTOAST\_TYPES\= \['info', 'success', 'warning', 'error'\]
// 持续时间(ms)
constDEFAULT\_DURATION\=3000
classToastextendsComponent {
state\= {
zIndex:100, // 防止被遮盖
top:0, // 距离顶部的位置(px)
defaultDuration:DEFAULT\_DURATION, // 提示持续的时间(ms)
list: \[\], // 提示内容列表
}
setConfig\= (config\= {}) \=> {
const { zIndex\=100, top\=0, defaultDuration\=DEFAULT\_DURATION } \=config
this.setState({ zIndex, top, defaultDuration })
}
/\*\*
\* @description 添加提示
\*
\* @param{Object}options 选项
\* @param{String}options.type 类型 enum: TOAST\_TYPES
\* @param{String}options.content 内容
\* @param{Number}options.duration 持续时间
\*/
add\= (options\= {}) \=> {
const { list, defaultDuration } \=this.state
constid\=Date.now()
constitem\= { id, ...options }
this.setState({ list:list.concat(item) }, () \=> {
consttimer\=setTimeout(() \=> {
clearTimeout(timer)
this.setState(prev\=> ({ list:prev.list.filter(v\=>v.id!==id) }))
}, options.duration||defaultDuration)
})
}
render() {
const { zIndex, top, list } \=this.state
if (!Array.isArray(list)) {
returnfalse
}
return (
<divclassName\="top-toast--container"style\={{ zIndex, top }}\>
<TransitionGroupclassName\="top-toast--wrapper"\>
{list.map(v\=> (
<CSSTransitionkey\={v.id}timeout\={ANIMATION\_DURATION\_TIME}classNames\="fade"\>
<div\>
<divclassName\="top-toast--item-content"\>
<iclassName\="item-ico"style\={{ backgroundImage:getIco(v.type) }}/>
<span\>{v.content}</span\>
</div\>
</div\>
</CSSTransition\>
))}
</TransitionGroup\>
</div\>
)
}
}
//自动获取组件挂载节点
functiongetContainer() {
constid\='toast-container-element'
letelContainer\=document.getElementById(id)
if (!elContainer) {
elContainer\=document.createElement('div')
elContainer.setAttribute('id', id)
}
returnelContainer
}
//获取挂载节点的父容器
functiongetRenderNode() {
returndocument.getElementsByTagName('body')\[0\]
}
// 获取对应图标
functiongetIco(type) {
switch (type) {
case'success':
return\`url("${icoSuccess}")\`
case'warning':
return\`url("${icoWarning}")\`
case'error':
return\`url("${icoError}")\`
default:
return\`url("${icoInfo}")\`
}
}
functionmount() {
constcontainer\=getContainer()
getRenderNode().appendChild(container)
ReactDOM.render(<Toastref\={onComponentInit}/>, container)
}
// 暴露出去的api方法集合
constapi\= {}
functiononComponentInit(ins\=null) {
TOAST\_TYPES.forEach(type\=> {
api\[type\] \= (arg\=null) \=> {
// 可传入'string'或'object'类型
if (!arg) {
return
}
if (typeofarg\==='object') {
const { content\='', duration\=DEFAULT\_DURATION } \=arg
ins.add({ type, content, duration })
} elseif (typeofarg\==='string') {
ins.add({ type, content:arg })
}
}
})
// 配置config
api.config\=config\=>ins.setConfig(config)
}
// 执行挂载函数(仅一次)
mount()
exportdefaultapi
样式文件(.less)
Toast/styles.less
@item-size: 30px;
@spacing: 5px;
@ico-size: 16px;
@time: 250ms;
.top-toast--container {
position: fixed;
// top: 0;
left: 0;
right: 0;
padding: 10px;
pointer-events: none;
}
.top-toast--wrapper {
display: flex;
flex-direction: column;
align-items: center;
list-style: none;
margin: 0;
padding-left: 0;
}
.top-toast--item-content {
position: relative;
display: flex;
align-items: center;
height: @item-size;
padding: 010px020+@ico-size;
margin-bottom: @spacing;
border-radius: 4px;
background-color: #fff;
box-shadow: 04px12pxrgba(0, 0, 0, 0.15);
font-size: 14px;
line-height: @item-size;
color: rgba(0, 0, 0, 0.65);
\>.item-ico {
position: absolute;
top: 50%;
left: 10px;
display: block;
width: @ico-size;
height: @ico-size;
transform: translateY(\-50%);
background: center/coverno-repeat;
}
}
.fade-enter {
opacity: 0;
height: 0;
transform: translateY(-@item-size);
}
.fade-enter-active {
position: relative;
opacity: 1;
height: @item-size+@spacing;
transform: translateY(0);
transition: all@timeease-in-out;
}
.fade-exit {
opacity: 1;
height: @item-size+@spacing;
transition: all@timeease-in-out;
}
.fade-exit-active {
opacity: 0;
height: 0;
transition: all@timeease-in-out;
}
使用
import Toast from'@/components/Toast'
// 父组件
Toast.info("提示内容")
Toast.success({content:"对象形式参数", duration: 5000})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。