React 使用Portals手写模态框Dialog

如何引用Protals

Portabls是ReactDom中的方法,通过ReactDom.createPortal(child,dom)使用的
child:任何可渲染的 React元素
dom:当前绑定于哪个DOM元素中

Portabls作用

某些情况下,我们想将某些内容独立于父组件,甚至于当前挂在DOM元素中root等。


使用手写dialog模态框示例:

index.html页面

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
  
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <div id="model"></div>

  </body>
</html>

在index.html中加入DOM元素,id取名为model,后期做Portals DOM绑定


model.js 组件,弹窗组件

import  { PureComponent } from 'react';
import { createPortal } from 'react-dom';
import propTypes from 'prop-types';
import './index.css';
export default class Model extends PureComponent {
    static propTypes={
        title:propTypes.string,
        width:propTypes.string,
        top:propTypes.string,
        show:propTypes.bool.isRequired,
        closeModel:propTypes.func
    }
    static defaultProps={
        title:'标题',
        width:'30%',
        top:'15vh',
        show:false
    }
    constructor(props){
        super(props)
    }
    render() {
        const { children,title,width,top,show , closeModel }=this.props;
        const modelChild=(
        <div className={ ` ${show?'active':''} model-container` }>
            <div className={ ` ${show?'active':''} h-model` }
              style={ {top,width,left:`calc(50% - ${parseFloat(width)/2}%)`} }>
                <div className="model-header">
                    <h2>{ title }</h2>
                    <i onClick={ closeModel }>x</i>
                </div>
                <div className="model-aside">{children}</div>

                <div className="model-footer">
                        <button className="btn del">取消</button>
                        <button className="btn sure">确定</button>
                </div>
            </div>
        </div>
        )
        return createPortal(
            modelChild,
            document.getElementById('model')
        )
    }
}

将props.child抽离出来,放在modelChild重新进行渲染,通过ES6结构语法,将createPortal方法拿出来进行使用。
createPortal第一个参数:modelChild表示,绑定需要渲染的组件。
createPortal第二个参数:表示,将组件放入改DOM内部。


DemoBlock.js 组件,内部事件点击渲染Dialog组件

import React, { PureComponent } from 'react'
import './index.css'
import Model from '../Model/index';
export default class DemoBlock extends PureComponent {
    constructor(props){
        super(props)
        this.state={
            show:false
        }
    }
    render() {
        const { show } = this.state;
        return (
            <div className="demo-block">
                 <Model closeModel={ this.closeModel.bind(this) }  show={ show }>
                    {
                        <p>这是一段段落描述</p>
                    }
                </Model>

                <h3>这里是测试模块</h3>
                <button onClick={ ()=>this.open(show) }>弹窗测试</button>
            </div>
        )
    }
    closeModel(){
        console.log('执行了关闭')
        this.setState({
            show:false
        })
    }
    open(type){
        console.log('开始执行')
        this.setState({
            show:!type
        })
    }
}

Model组件内部标签,在Model中都可以通过props.children获取到


渲染后成果,当然样式还是要自己写,主要梳理功能

chrome-capture-2022-4-12.gif
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容