这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战css
React 实现对话框有两种方案:html
在实际开发中,咱们大多会选择直接使用 Antd 的对话框组件,其实 Antd 对话框的实现也是基于 React Portals 这个特性,因此了解它能够让咱们的漂浮层之路走的更宽哦:react
Portal
是 React 16.3 新引入的 API,React 是在内存中维护了一棵 Virtual Dom Tree ,这棵树会映射到真实的 Dom 节点,而 Portal
能够打断这种映射关系,它提供了一种将子节点渲染到存在于父组件之外的 DOM
节点的优秀的方案,一举解决了漂浮层的问题,如:Dialog、Tooltip 等。markdown
ReactDOM.createPortal(child, container);
复制代码
第一个参数(child
)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container
)是一个 DOM 元素。antd
须要注意,虽然 child 看似显示在另外一颗 Dom 树上,但在 Virtual Dom 中,实际上是同一棵,在下面的例子中也会看到。app
按照官网文档,上手很是简单dom
import React, { useState } from 'react';
import { Modal, Button } from 'antd';
const DialogPage = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const showModal = () => {
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
};
const handleCancel = () => {
setIsModalVisible(false);
};
return (
<> <Button type="primary" onClick={showModal}> Open Antd Modal </Button> <Modal title="Basic Modal" visible={isModalVisible} onOk={handleOk} onCancel={handleCancel} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </>
);
};
export default DialogPage;
复制代码
在 index.html 中,建立一个 dialog 的容器元素:ide
<div id="root"></div>
<div id="dialog-root"></div>
复制代码
经过组件内部状态(visible
) 控制 Dialog 的渲染:oop
{
visible
? createPortal(
<div className="portal-sample"> {children} <Button onClick={onHide}>close</Button> </div>,
document.getElementById('dialog-root'),
)
: null;
}
复制代码
从 React Components 能够看出来,PortalDialog 和 DialogPage 的父子关系依然存在:post
import React, { useState } from 'react';
import { Button } from 'antd';
import PortalDialog from '@/components/PortalDialog';
const DialogPage = () => {
const [isPortalVisible, setIsPortalVisible] = useState(false);
const showPortal = () => {
setIsPortalVisible(true);
};
const hidePortal = () => {
setIsPortalVisible(false);
};
return (
<> <Button style={{ marginLeft: '20px' }} onClick={showPortal}> Open Dialog(React Portals) </Button> <PortalDialog visible={isPortalVisible} onHide={hidePortal}> <div>dialog-children</div> </PortalDialog> </>
);
};
export default DialogPage;
复制代码
import { createPortal } from 'react-dom';
import { Button } from 'antd';
import './style.css';
const PortalDialog = (props) => {
const { visible, children, onHide } = props;
return visible
? createPortal(
<div className="portal-sample"> {children} <Button onClick={onHide}>close</Button> </div>,
document.getElementById('dialog-root'),
)
: null;
};
export default PortalDialog;
复制代码
.portal-sample {
position: absolute;
padding: 20px;
width: 500px;
height: 300px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 10px;
border: 1px solid #ddd;
box-shadow: 0px 0px 20px 2px #ddd;
}
复制代码