Heim  >  Artikel  >  Web-Frontend  >  So implementieren Sie eine modale Popup-Box in React

So implementieren Sie eine modale Popup-Box in React

藏色散人
藏色散人Original
2023-01-19 15:43:071205Durchsuche

So implementieren Sie eine modale Popup-Box in React: 1. Verwenden Sie createPortal, um das Element direkt unter „document.body“ zu rendern. 2. Verwenden Sie „modelShow“ und „modelShowAync“, um die Anzeige und das Ausblenden des Popups zu steuern. up-Fenster; 3. Verwenden Sie ein Steuerelement. Verwenden Sie einfach controlShow, um die Aktualisierungsaufgabe reibungslos auszuführen.

So implementieren Sie eine modale Popup-Box in React

Die Betriebsumgebung dieses Tutorials: Windows 10-System, Reaktionsversion 18.0.0, Dell G3-Computer.

Wie implementiert man ein modales Popup-Fenster?

React implementiert ein modales Popup-Fenster

1. Dialog.js-Datei

import React, {useMemo, useEffect, useState} from 'react'
import ReactDOM from 'react-dom'
/**
 *
 * 需要把元素渲染到组件之外,用 createPortal 把元素直接渲染到 document.body 下,为了防止函数组件每一次执行都触发 createPortal, 所以通过 useMemo 做性能优化。
 因为需要渐变的动画效果,所以需要两个变量 modelShow / modelShowAync 来控制显示/隐藏,modelShow 让元素显示/隐藏,modelShowAync 控制动画执行。
 当弹窗要显示的时候,要先设置 modelShow 让组件显示,然后用 setTimeout 调度让 modelShowAync 触发执行动画。
 当弹窗要隐藏的时候,需要先让动画执行,所以先控制 modelShowAync ,然后通过控制 modelShow 元素隐藏,和上述流程相反。
 用一个控制器 controlShow 来流畅执行更新任务。
 */
// 控制弹窗隐藏以及动画效果
const controlShow = (f1, f2, value, timer) => {
    f1(value)
    return setTimeout(() => {
        f2(value)
    }, timer)
}
export const Dialog = (props) => {
    const {width, visible, closeCb, onClose} = props
    // 控制 modelShow动画效果
    const [modelShow, setModelShow] = useState(visible)
    const [modelShowAsync, setModelShowAsync] = useState(visible)
    const renderChildren = useMemo(() => {
        // 把元素渲染到组件之外的document.body 上
        return ReactDOM.createPortal(<div style={{display: modelShow ? &#39;block&#39; : &#39;none&#39;}}>
            <div className="model_container" style={{opacity: modelShowAsync ? 1 : 0}}>
                <div className="model_wrap">
                    <div style={{width: width + &#39;px&#39;}}> {props.children} </div>
                </div>
            </div>
            <div className="model_container mast" onClick={() => onClose && onClose()}
                 style={{opacity: modelShowAsync ? 0.6 : 0}}/>
        </div>, document.body)
    }, [modelShow, modelShowAsync])
    useEffect(() => {
        let timer
        if (visible) {
            // 打开弹窗,
            timer = controlShow(setModelShow, setModelShowAsync, visible, 30)
        } else {
            timer = controlShow(setModelShowAsync,setModelShow,visible,1000)
        }
        return () => {
            timer && clearTimeout(timer)
        }
    }, [visible])
    return renderChildren
}

3 Stildatei

import {Dialog} from "./Dialog";
import React, {useEffect, useState} from &#39;react&#39;
import ReactDOM from &#39;react-dom&#39;
import &#39;./style.scss&#39;
class Modal extends React.PureComponent {
    // 渲染底部按钮
    renderFooter = () => {
        const {onOk, onCancel, cancelText, okText, footer} = this.props
        //    触发onOk / onCancel回调
        if (footer && React.isValidElement(footer)) return footer
        return <div className="model_bottom">
            <div className="model_btn_box">
                <button className="searchbtn"
                        onClick={(e) => {
                            onOk && onOk(e)
                        }}>{okText || &#39;确定&#39;}
                </button>
                <button className="concellbtn"
                        onClick={(e) => {
                            onCancel && onCancel(e)
                        }}>{cancelText || &#39;取消&#39;}
                </button>
            </div>
        </div>
    }
    // 渲染底部
    renderTop = () => {
        const {title, onClose} = this.props
        return <div className="model_top">
            <p>{title}</p>
            <span className="model_top_close" onClick={() => onClose && onClose()}>X</span>
        </div>
    }
    // 渲染弹窗内容
    renderContent = () => {
        const {content, children} = this.props
        return React.isValidElement(content) ? content : children ? children : null
    }
    render() {
        const {visible, width = 500, closeCb, onClose} = this.props
        return <Dialog
            closeCb={closeCb}
            onClose={onClose}
            visible={visible}
            width={width}
        >
            {this.renderTop()}
            {this.renderContent()}
            {this.renderFooter()}
        </Dialog>
    }
}
// 静态方法
let ModalContainer = null
const modelSymbol = Symbol(&#39;$$_model_Container_hidden&#39;)
// 静态属性show——控制
Modal.show = (config) => {
    //  如果modal已经存在,name就不需要第二次show
    if (ModalContainer) return
    const props = {...config, visible: true}
    const container = ModalContainer = document.createElement(&#39;div&#39;)
    // 创建一个管理者,管理model状态
    const manager = container[modelSymbol] = {
        setShow: null,
        mounted: false,
        hidden() {
            const {setShow} = manager
            setShow && setShow(false)
        },
        destroy() {
            //    卸载组件
            ReactDOM.unmountComponentAtNode(container)
            // 移除节点
            document.body.removeChild(container)
            // 置空元素
            ModalContainer = null
        }
    }
    const ModelApp = (props) => {
        const [show, setShow] = useState(false)
        manager.setShow = setShow
        const {visible, ...trueProps} = props
        useEffect(() => {
            // 加载完成,设置状态
            manager.mounted = true
            setShow(visible)
        }, [])
        return <Modal {...trueProps} closeCb={() => manager.mounted && manager.destroy()} visible={show}/>
    }
    // 插入到body中
    document.appendChild(container)
    // 渲染React元素
    ReactDOM.render(<ModelApp/>, container)
    return manager
}
Modal.hidden = () => {
    if(!ModalContainer) return
    // 如果存在ModalContainer 那么隐藏ModalContainer
    ModalContainer[modelSymbol] && ModalContainer[modelSymbol].hidden()
}
export default Modal

4. Rufen Sie das Beispiel auf

$bg-linear-gradien-red-light : linear-gradient(135deg, #fc4838 0%, #f6346b  100%);
$bg-linear-gradien-red-dark : linear-gradient(135deg, #fc4838 0%, #f6346b  100%);
.constrol{
  padding: 30px;
  width: 500px;
  border: 1px solid #ccc;
  height: 200px;
}
.feel{
  padding: 24px;
}
.model_top{
  height: 40px;
  border-radius: 5px  5px 0 0 ;
  position: relative;
  p{
    height: 40px;
    font-weight: bold;
    line-height: 40px;
    padding-left: 14px;
  }
  background-color: #eee;
  .model_top_close{
    position: absolute;
    font-size: 16px;
    cursor: pointer;
    right: 24px;
    top: 8px;
  }
}
.model_bottom{
  height: 50px;
  padding-top: 10px;
  .model_btn_box{
    display: inline-block;
    margin-left: 50%;
    transform: translateX(-50%);
  }
}
.model_container{
  .model_wrap{
    position: absolute;
    border-radius:5px ;
    background: #fff;
    left:50%;
    top:50%;
    transform: translate(-50%,-50%);
  }
  position: fixed;
  z-index: 10000;
  left:0;
  top:0;
  transition: opacity 0.3s;
  right: 0;
  bottom: 0;
}
.mast{
  background-color: #000;
  z-index: 9999;
}
.searchbtn{
  background: linear-gradient(135deg, #fc4838 0%, #f6346b  100%);
  color: #fff;
  min-width: 96px;
  height :36px;
  border :none;
  border-radius: 18px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  margin-left: 20px !important;
}
.searchbtn:focus{
  background: $bg-linear-gradien-red-dark;
  color: #fff;
  min-width: 96px;
  height: 36px;
  border: none;
  border-radius: 18px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  margin-left: 20px !important;
  box-shadow: 0 2px 7px 0 #FAA79B;
}
.searchbtn:hover{
  background :$bg-linear-gradien-red-light;
  color :#fff;
  min-width: 96px;
  height :36px;
  margin-left: 20px !important;
  border: none;
  border-radius: 18px;
  font-size :14px;
  font-weight: 500;
  cursor: pointer;
  box-shadow: 0 2px 7px 0 #FAA79B;
}
.searchbtn:disabled{
  background: #c0c6c6;
  color :#fff;
  min-width: 96px;
  height :36px;
  font-size :14px;
  font-weight: 500;
  border: none;
  border-radius: 18px;
  cursor: not-allowed;
}
.concellbtn{
  background :#fff;
  color :#303133;
  width: 96px;
  height: 36px;
  font-size: 14px;
  font-weight: 500;
  border :1px solid #E4E7ED;
  border-radius: 18px;
  cursor: pointer;
  // margin-right: 10px;
  margin-left: 10px;
}
.concellbtn:hover{
  background :rgba(220, 223, 230, 0.1);
  color: #303133;
  width :96px;
  height: 36px;
  font-size: 14px;
  font-weight: 500;
  border :1px solid #E4E7ED;
  border-radius: 18px;
  cursor: pointer;
  // margin-right: 10px;
  margin-left: 10px;
}
.concellbtn:focus{
  background :rgba(220, 223, 230, 0.24);
  color: #303133;
  width :96px;
  height: 36px;
  font-size: 14px;
  font-weight: 500;
  border: 1px solid #C0C4CC;
  border-radius: 18px;
  cursor: pointer;
  margin-right: 10px;
  margin-left: 10px;
}

, um den Effekt zu erzielen

Empfohlenes Lernen: „So implementieren Sie eine modale Popup-Box in ReactVideo-Tutorial reagieren

Das obige ist der detaillierte Inhalt vonSo implementieren Sie eine modale Popup-Box in React. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn