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的过程
React弹窗组件的更多相关文章
- 实现一个带有动效的 React 弹窗组件
我们在写一些 UI 组件时,若不考虑动效,就很容易实现,主要就是有无的切换(类似于 Vue 中的 v-if 属性)或者可见性的切换(类似于 Vue 中的 v-show 属性). 1. 没有动效的弹窗 ...
- 封装React AntD的dialog弹窗组件
前一段时间分享了基于vue和element所封装的弹窗组件(封装Vue Element的dialog弹窗组件),今天就来分享一个基于react和antD所封装的弹窗组件,反正所使用的技术还是那个技术, ...
- beeshell —— 开源的 React Native 组件库
介绍 beeshell 是一个 React Native 应用的基础组件库,基于 0.53.3 版本,提供一整套开箱即用的高质量组件,包含 JavaScript(以下简称 JS)组件和复合组件(包含 ...
- 移动web端的react.js组件化方案
背景: 随着互联网世界的兴起,web前端开发的方式越来越多,出现了很多种场景开发的前端架构体系,也对前端的要求日益增高,早已经不是靠一个JQuery.js来做前端页面的时代了,而今移动端变化最大,近 ...
- Griddle, griddle-react 一个REACT 表格组件
Griddle, griddle-react 一个REACT 表格组件: http://griddlegriddle.github.io/Griddle/index.html
- React Native组件之Text
React Native组件之Text相当于iOS中的UILabel. 其基本属性如下: /** * Sample React Native App * https://github.com/face ...
- React Native组件之Switch和Picker和Slide
React Native组件Switch类似于iOS中的UISwitch:组件Slide类似于iOS中UIslider,组件Picker类似于iOS的UIPickerView.他们的使用方法和相关属性 ...
- reactjs入门到实战(七)---- React的组件的生命周期
React的组件的生命周期有三个状态分别是:挂载(生产组件示例化.准备挂载到页面.挂载到页面).更新(更新值.更新DOM).和卸载(卸载后). >>>其他 getInitia ...
- React Native 组件之TextInput
React Native 组件之TextInput类似于iOS中的UITextView或者UITextField,是作为一个文字输入的组件,下面的TextInput的用法和相关属性. /** * Sa ...
随机推荐
- uoj118 【UR #8】赴京赶考
题目 不难发现我们直接走过去就行了 考虑到第\(i\)行的构造方法就是把\(b\)数组作为模板,每个数和\(a_i\)异或一下就可以了 于是不难发现对于一段连续相等的\(a\),它们在矩阵上就形成了完 ...
- [POI2011]SMI-Garbage
题目描述 http://main.edu.pl/en/archive/oi/18/smi The Byteotian Waste Management Company (BWMC) has drast ...
- Docker学习のWindows下如何访问Docker本身的虚拟机
获取可访问Docker守护程序的容器 docker run --privileged -it -v /var/run/docker.sock:/var/run/docker.sock jongalla ...
- JS函数 编程练习 使用javascript代码写出一个函数:实现传入两个整数后弹出较大的整数。
编程练习 使用javascript代码写出一个函数:实现传入两个整数后弹出较大的整数. 任务 第一步: 编写代码完成一个函数的定义吧. 第二步: 我们来补充函数体中的控制语句,完成函数功能吧. 提示: ...
- wordpress 获取所有管理员的邮箱
function get_administrator_email(){ $blogUsers = get_users('role=Administrator'); $adminEmails = arr ...
- 关于如何正确打开.wlf文件
只简单说明一下保存/打开.wlf需要注意的内容. (1) 保存 在GUI界面保存时,先切换到sim窗口: 用命令行保存时,其格式为: vsim –wlf <wave_file> … (2) ...
- thinkphp url大小写
系统默认的规范是根据URL里面的模块名.控制器名来定位到具体的控制器类的,从而执行控制器类的操作方法. 以URL访问 http://serverName/index.php/Home/Index/in ...
- VC中编辑框更新SetDlgItemText()与UpdateData()的区别
SetDlgItemText(IDC_EDIT_RXDATA,m_strREData); //前一个是ID号,后一个是编辑框的成员变量 UpdateData(FALSE); 它们都能更新编辑框的 ...
- linxu(centos)安装nginx
安装make: yum -y install gcc automake autoconf libtool make 安装g++: yum install gcc gcc-c++ 下面正式开始 ---- ...
- vue.js+element ui Table+spring boot增删改查
小白初学,不懂的还是太多了,找了好多资料才做出来的先记录一下 1.先用Spring boot创建一个包含了增删改查的项目 2.创建vue.js项目 3.安装Element UI (1)进入项目文件夹下 ...