zoukankan      html  css  js  c++  java
  • React弹窗组件

    原文地址 小寒的博客

    这里的弹窗泛指所有的弹出组件,这些组件不受页面其他UI布局影响,处于DOM结构的顶层,绝对定位在body元素下。

    这个特殊性也给它的开发提出了特殊的要求。

    react新版本中的createPortal Api可以很方便的制造一个组件到制定的dom里。

    在componentDidMount中进行ReactDOM.render方法是一个很巧妙的技巧。

    话不多说,开始贴代码

    1. 在componentDidMount去渲染dom

    class Modal extends React.Component {
      el = null
    
      componentDidMount() {
        this.el = createElementToModalRoot()
        renderModal(this.el, this.props)
      }
    
      componentDidUpdate() {
        renderModal(this.el, this.props)
        if (!this.props.visible) {
          unRenderModal(this.el)
        }
      }
    
      componentWillUnMount() {
        unRenderModal(this.el)
      }
    
      render() {
        return null
      }
    }

    上边的代码就是弹窗的核心思想,首先创建element在root元素下,然后渲染dom,在unmount或者visible属性为false的时候,卸载弹窗

    而更新属性也是通过重新render去渲染的,由于react伟大的diff算法,我们即使ReactDOM.render重新渲染也不会导致页面刷新,而只是属性的变化引起的页面变动

    2. createElementToModalRoot方法

    function createElementToModalRoot() {
      let modalRoot
    
      modalRoot = document.getElementById('modal-root')
      if (!modalRoot) {
        modalRoot = document.createElement('div')
        modalRoot.setAttribute('id', 'modal-root')
    
        const modalMask = document.createElement('div')
        modalMask.setAttribute('id', 'modal-mask')
        document.body.appendChild(modalRoot)
        modalRoot.appendChild(modalMask)
      }
    
      const el = document.createElement('div')
      modalRoot.appendChild(el);
      return el
    }

    用dom方法创建元素,因为此时componentDidMount所以我们可以肆无忌惮的进行dom操作了,执行这个方法之后我们会创建#modal-root #modal-mask 以及 待会render的dom元素

    3. renderModal方法

    const renderModal = (el, props) => {
      const modalRoot = document.getElementById('modal-root')
      const modalMask = document.getElementById('modal-mask')
    
      modalMask.style.display = 'block'
      modalRoot.style.display = 'block'
    
      ReactDOM.render(<ModalInner {...props} />, el)
    }

    上面添的代码我们用ModalInner组件创建了一个去渲染了添加在#modal-root下面的dom,每次更新组件,也是通过他再次渲染

    4. ModalInner组件

    class ModalInner extends React.Component {
      render() {
        const { children, title, visible, onCancel, onOk } = this.props
    
        return (
          <div className={classnames('modal', visible ? 'modal-animate-in' : 'modal-animate-out')}>
            <div className="modal-head">
              <div className="modal-title">{title}</div>
              <div className="modal-cancel-btn" onClick={onCancel}>+</div>
            </div>
            <div className="modal-content">
              {children}
            </div>
            <div className="modal-footer">
              <button className="do-btn" onClick={onCancel}>取消</button>
              <button className="do-btn do-btn-primary" onClick={onOk}>确定</button>
            </div>
          </div>
        )
      }
    }

    这个组件,我们设置了最常用的一些属性,包括title children visible 和 onCancel onOk

    5. unRenderModal方法

    最后我们就剩下卸载方法了

    const unRenderModal = (el) => {
      const modalRoot = document.getElementById('modal-root')
      const modalMask = document.getElementById('modal-mask')
    
      modalMask.style.display = 'none'
      modalRoot.style.display = 'none'
    
      modalRoot.removeChild(el);
    }
     

    6. 添加动画上边的ModalInner组件里可以看到他会根据visible对dom添加不同的animate从而产生动画

    但是如果unRenderModal方法会直接移除dom,所以不会产生移除动画

    所以我们把上边的componentDidMount修改一下

    componentDidUpdate() {
        renderModal(this.el, this.props)
    
        if (!this.props.visible) {
          setTimeout(() => unRenderModal(this.el), 500)
        }
      }
     

    7. Modal.open方法

    Modal.open = option => {
      const props = {...option}
      const el = createElementToModalRoot()
      const close = () => {
        option.visible = false
        renderModal(el, option)
        setTimeout(() => unRenderModal(el), 500)
      }
    
      props.visible = true
      props.children = option.content
      props.onOk = e => {
        option.onOk ? option.onOk(e, close) : close()
      }
      props.onCancel = () => {
        option.ononCancel ? option.ononCancel(e, close) : close()
      }
    
      renderModal(el, props)
    }

    还是用的上面的那些api,这是visible属性是我们手动传入组件里的

    这样我们就可以通过非api的形式去打开一个弹窗了

    以上便是render方法创建弹窗的方式,当然很推荐使用createPortal方法,可以省去手动render和unRender的过程

  • 相关阅读:
    【思考题】任意长度有理数乘法运算
    【排序】表插入排序算法(C语言版)
    JAVA中的反射
    JAVA中关于日期的最常见的操作
    Hibernate:基于HQL实现数据查询
    Hibernate与Mybatis对比
    使用idea实现SSM框架整合
    基于maven搭建hibernate运行环境
    MYSQL中的存储过程
    MySQL 索引
  • 原文地址:https://www.cnblogs.com/sowhite/p/9974472.html
Copyright © 2011-2022 走看看