需求分析
很多时候我们需要通过弹窗/对话框来完成交互,因此这个公共的弹窗组件需要实现以下功能:
- 组件动态地传入弹窗的标题和内容
- 点击确定和取消按钮之后,执行组件传入的回调函数
样式布局
JSX代码如下:(通过 styled-components 开发样式)
const JSXdom = (
<div>
<Mask />
<ModalWrapper>
<ModalContent>
<p className="title">{title}</p>
<div className="content">{tips}</div>
<BtnGroup >
<div
className="btn left"
onClick={() => this.onCancel(handleCancel)}
>取消</div>
<div
className="btn right"
onClick={() => this.onOk(handleOk)}
>确定</div>
</BtnGroup>
</ModalContent>
</ModalWrapper>
</div>
)
首先我们需要一个遮住层Mask作为背景,实现页面背景变暗的效果
export const Mask = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
background-color: rgba(0, 0, 0, 0.65);
z-index: 1000;
`
然后用过绝对定位 + transform 实现弹窗的水平垂直居中
并对标题、内容、确认和取消按钮进行简单的布局
export const ModalWrapper = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
`
export const ModalContent = styled.div`
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 20px 20px 0 20px;
60%;
background-color: #fff;
border-radius: 4px;
text-align: center;
.title {
font-size: 18px;
margin-bottom: 15px;
}
.content {
100%;
font-size: 14px;
line-height: 20px;
margin-bottom: 15px;
word-wrap: break-word;
}
`
export const BtnGroup = styled.div`
display: flex;
align-items: center;
text-align: center;
font-size: 14px;
.btn {
flex: 1;
line-height: 22px;
padding: 10px 0;
border-top: 1px solid whitesmoke;
background-color: #fff;
&.left {
border-right: 1px solid whitesmoke;
}
}
`
核心函数
核心函数的职责如下:
- 创建一个空的div节点(createElement)
- 将上述JSX渲染到div节点上(ReactDom.render)
- 将div节点挂载到body上(appendChild)
代码如下:
success() {
this.dom = document.createElement('div')
const JSXDOM = ()
ReactDom.render(JSXDOM,this.dom)
document.dody.appendChild(this.dom)
}
这样,我们就成功将弹窗渲染到页面上了
回调函数
当用户点击确定或取消时,我们必须将控制权交还给 调用弹窗的组件,由组件来执行后续的操作
因此,success函数需要接收 handleOk 和 handleCancel 这两个函数作为参数
为了使得弹窗消失,我们还需要再封装 onOk 和 onCancel 函数,让他们去调用组件的回调函数,并且清除this.dom
首先将清除dom的任务封装成一个辅助函数 removeDom
removeDom() {
this.dom && this.dom.remove()
/*
写法等同于
if(this.dom){
this.dom.remove()
}
*/
}
然后编写onOk和onCancel函数
onOk(handleOk) {
(handleOk instanceof Function) && handleOk()
this.removeDom()
}
onCancel (handleCancel) {
(handleCancel instanceof Function) && handleCancel()
this.removeDom()
}
完整的代码如下:
import React from 'react'
import ReactDOM from 'react-dom'
import {
Mask,
ModalWrapper,
ModalContent,
BtnGroup
} from './style'
export default {
dom: null,
success ({title,tips,handleOk,handleCancel}) {
this.removeDom()
this.dom = document.createElement('div')
const JSXdom = (
<div>
<Mask />
<ModalWrapper>
<ModalContent>
<p className="title">{title}</p>
<div className="content">{tips}</div>
<BtnGroup >
<div
className="btn left"
onClick={() => this.onCancel(handleCancel)}
>取消</div>
<div
className="btn right"
onClick={() => this.onOk(handleOk)}
>确定</div>
</BtnGroup>
</ModalContent>
</ModalWrapper>
</div>
)
ReactDOM.render(JSXdom,this.dom)
document.body.appendChild(this.dom)
},
onCancel (handleCancel) {
(handleCancel instanceof Function) && handleCancel();
this.removeDom()
},
onOk (handleOk) {
(handleOk instanceof Function) && handleOk();
this.removeDom()
},
removeDom() {
this.dom && this.dom.remove()
}
}
组件调用
import Modal from './xxx.js'
class W extends from Component {
render(){
return(
<div onClick={this.handleClick}>点击</div>
)
}
handleClick() {
Modal.success({
title: '标题',
tips: '测试弹窗',
handleOk: () => {
console.log('Ok')
},
handleCancel: () => {
console.log('Cancel')
}
})
}
}
注意:组件传入的 hanldleOk 和 handleCancel 最好使用箭头函数的方式来定义
这样才能确保函数在执行的时候,this的指向为当前组件