React封装公共函数:弹窗

需求分析

很多时候我们需要通过弹窗/对话框来完成交互,因此这个公共的弹窗组件需要实现以下功能:

  • 组件动态地传入弹窗的标题和内容
  • 点击确定和取消按钮之后,执行组件传入的回调函数

样式布局

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;
  width: 60%;
  background-color: #fff;
  border-radius: 4px;
  text-align: center;
  .title {
    font-size: 18px;
    margin-bottom: 15px;
  }
  .content {
    width: 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;
    }
  }
`

核心函数

核心函数的职责如下:

  1. 创建一个空的div节点(createElement)
  2. 将上述JSX渲染到div节点上(ReactDom.render)
  3. 将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的指向为当前组件

posted @ 2021-02-11 14:13  BAEBAE996  阅读(836)  评论(0编辑  收藏  举报