react实现弹出模态框的方法:1、用createportal把元素直接渲染到“document.body”下;2、通过“modelshow”和“modelshowaync”来控制弹窗的显示隐藏;3、用一个控制器controlshow来流畅执行更新任务即可。
本教程操作环境:windows10系统、react18.0.0版、dell g3电脑。
react怎么实现弹出模态框?
react实现modal弹窗
一、dialog.js文件
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 ? 'block' : 'none'}}> <div classname="model_container" style={{opacity: modelshowasync ? 1 : 0}}> <div classname="model_wrap"> <div style={{width: width + 'px'}}> {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}
二、modal.js
import {dialog} from "./dialog";import react, {useeffect, usestate} from 'react'import reactdom from 'react-dom'import './style.scss'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 || '确定'} </button> <button classname="concellbtn" onclick={(e) => { oncancel && oncancel(e) }}>{canceltext || '取消'} </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 = nullconst modelsymbol = symbol('$$_model_container_hidden')// 静态属性show——控制modal.show = (config) => { // 如果modal已经存在,name就不需要第二次show if (modalcontainer) return const props = {...config, visible: true} const container = modalcontainer = document.createelement('div') // 创建一个管理者,管理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
三、style.scss样式文件
$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;}
四、调用例子
import react, {usestate, usememo} from 'react'import modal from './custompopup/modal'/* 挂载方式调用modal */export default function app() { const [ visible , setvisible ] = usestate(false) const [ nameshow , setnameshow ] = usestate(false) const handleclick = () => { setvisible(!visible) setnameshow(!nameshow) } /* 防止 model 的 purecomponent 失去作用 */ const [ handleclose ,handleok, handlecancel ] = usememo(()=>{ const ok = () => console.log('点击确定按钮') const close = () => setvisible(false) const cancel = () => console.log('点击取消按钮') return [close , ok , cancel] },[]) return <div> <modal oncancel={handlecancel} onclose={handleclose} onok={handleok} title={'标题'} visible={visible} width={700} > <div classname="feel" > 内容。。。。。。。 </div> </modal> <button onclick={() => { setvisible(!visible) setnameshow(false) }} > model show </button> <button onclick={handleclick} > model show ( 显示作者 ) </button> </div>}
实现效果
推荐学习:《react视频教程》
以上就是react怎么实现弹出模态框的详细内容。