手动实现React Modal组件(Portals)

本文以Antd中的 Modal组件作为案例剖析,重点讲述如何用 Portals手动实现Modal组件。

Antd中Modal组件效果展示

(1)简易版Modal使用--代码演示
import React, { Component } from 'react'
import {Modal,Button} from 'antd'
class DialogPage extends Component {
  state={
    isShow:false,
  }
  toggle=()=>{
    this.setState({
      isShow:!this.state.isShow
    })
  }
  handleOk=()=>{
    this.setState({
      isShow:false
    })
  }
  handleCancel=()=>{
    this.setState({
      isShow:false
    })
  }

  render () {
    return (
      

Some contents...

Some contents...

Some contents...

) } } export default DialogPage
(2)效果预览

手动实现React Modal组件(Portals)_第1张图片

请注意:代码中Modal组件与Button平齐。当dom渲染完成后,Modal组件与根结点root平齐。
概述:
弹窗类组件的要求弹窗内容在A处声明,却在B处展示。react中相当于弹窗内容看起来被render到一个组件里面去,实际改变的是网页上另一处的DOM结构,这个显然不符合正常逻辑。但是通过使用框架提供的特定API创建组件实例并指定挂载目标仍可完成任务。

手动实现简易版Modal组件

Portals提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案,这能够帮助我们解答上面的疑问。

(1)自定义Modal组件

// Modal组件
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import './modal.css'
import {createPortal} from 'react-dom'

class Modal extends Component {

  constructor (props){
    super(props)
    this.state={
      node:undefined
    }
  }

  static getDerivedStateFromProps(props, state){
    const document=window.document
    if(props.visible){ // visible 为true时,body中新增div,为createPortal提供一个挂载节点。
      const node=document.createElement('div')
      document.body.appendChild(node)
      return {
        node // 将挂载的Dom节点存储起来,方便移除时使用
      };
    }
    if(state.node){ // visible为false时,移除对应的dom
      document.body.removeChild(state.node)
    }
    return null
  }

  render () {
    const {visible,title,onOk,onCancel}=this.props
    if(!visible){
      return null;
    }
    return createPortal( //第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。
      
{ title&&(
{title}
) } {this.props.children}
, this.state.node ) } } Modal.propTypes={ visible:PropTypes.bool } Modal.defaultProps={ visible:true } export default Modal
// 自定义Modal使用页面
import React, { Component } from 'react'
import Modal from './Modal'
class ModalPage extends Component {
  state={
    isShow:false,
    isShow2:false
  }
  toggle=()=>{
    this.setState({
      isShow:!this.state.isShow
    })
  }
  handleOk=()=>{
    this.setState({
      isShow:false
    })
  }
  handleCancel=()=>{
    this.setState({
      isShow:false
    })
  }
  render () {
    return (
      

自定义Modal

自定义Modal

) } } export default ModalPage
.modalWrapper{
    position:absolute;
    z-index: 100;
    top:50%;
    left:50%;
    transform: translate(-50%,-50%);
    width:200px;
    border:1px solid red;
    text-align: center;
}
.modalTitle{
    border-bottom: 1px solid red;
}
.modalFooter{
    border-top: 1px solid red;
}

(2) 效果展示

手动实现React Modal组件(Portals)_第2张图片
如图所示,我们实现了Dom渲染穿越了层级。

(3) 概述

总的来说上面的Modal组件实现很容易,主要关注两点:
1.熟悉Portals的用法,可以看官方文档有更详细的解释。
2.关闭Modal时,同时移除对应Dom。代码中有对应的注释。

你可能感兴趣的:(react.js,前端)