1.主要API
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
参考:Portals
// 第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。
// 第二个参数(container)是一个 DOM 元素。
React.createPortal(child,container)2.具体实现
index.js
import React, { Component } from "react";
import { createPortal } from "react-dom";
import "./index.css";
export default class Modal extends Component {
// 监听父组件visible变化,控制modal组件的显示和隐藏
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.visible !== prevState.visible) {
return {
visible: nextProps.visible,
};
}
return null;
}
constructor(props) {
super(props);
// 创建modal组件挂载的节点
this.node = document.createElement("div");
document.body.appendChild(this.node);
this.state = {
visible: props.visible,
};
}
// 组件卸载前,移除挂载的节点
componentWillUnmount() {
document.body.removeChild(this.node);
}
onCancel = () => {
const { onCancel } = this.props;
onCancel && onCancel();
};
onOk = () => {
const { onOk } = this.props;
onOk && onOk();
};
render() {
const { title } = this.props;
const { visible } = this.state;
// 将modal组件挂载“跳出”当前dom节点
return createPortal(
visible && (
<div>
<div className="modal-mask"></div>
<div className="modal-wrap">
<div className="modal">
<div className="modal-close" onClick={this.onCancel}>
X
</div>
<div className="modal-header">{title}</div>
<div className="modal-body">{this.props.children}</div>
<div className="modal-footer">
<button onClick={this.onCancel}>取消</button>
<button onClick={this.onOk} className="btn-primary">
确定
</button>
</div>
</div>
</div>
</div>
),
this.node
);
}
}
index.css // 样式参考antd
.modal-mask{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1000;
height: 100%;
background-color: rgba(0,0,0,.45);
}
.modal-wrap{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1000;
overflow: auto;
outline: 0;
-webkit-overflow-scrolling: touch;
}
.modal{
box-sizing: border-box;
color: rgba(0,0,0,.65);
font-size: 14px;
line-height: 1.5715;
position: relative;
top: 100px;
width: 520px;
margin: 0 auto;
background-color: #fff;
}
.modal-header{
padding: 16px 24px;
border-bottom: 1px solid #f0f0f0;
text-align: center;
border-radius: 2px 2px 0 0;
}
.modal-close{
position: absolute;
top: 0;
right: 0;
padding: 16px 24px;
cursor: pointer;
}
.modal-body{
padding: 24px;
text-align: left;
}
.modal-footer{
padding: 16px 24px;
border-top: 1px solid #f0f0f0;
text-align: right;
}
.modal-footer button+button{
margin-left: 8px;
}
.modal-footer button{
position: relative;
font-weight: 400;
white-space: nowrap;
text-align: center;
background-image: none;
border: 1px solid #d9d9d9;
height: 32px;
padding: 4px 15px;
border-radius: 2px;
background-color: #fff;
cursor: pointer;
}
button.btn-primary{
background-color: #1890ff;
border-color: #1890ff;
color: #fff;
}