当我们在 React 中创建组件时,它们通常存在于组件树中。这大部分都很好,但有时我们希望组件的某些部分出现在组件树之外,或者完全不同的地方。
这是我们创建模态弹出窗口时的常见要求,它需要高于所有其他组件。
我们可以在一个组件中创建它们,但最终我们希望它们高于一切,并且将它们嵌套在许多组件中可能会导致问题,因为它们的z-index
将低于它们所在的位置:
为了解决这个问题,我们可以使用createPortal
将模态从它自己的组件中传送到模板的另一部分。
这允许我们将组件放置在我们想要的任何其他位置,例如 HTML 树的基础、 body
标签内或另一个元素内。
即使元素存在于组件树中, createPortal
也让我们能够将它放在我们喜欢的任何位置。
为了向您展示门户是如何工作的,请考虑我们的App.js
文件中有以下基本 React 代码。在这里,我们希望模态显示在其他所有内容之上。因此,我们创建了一个名为#modal-container
的div
。这最终是我们希望所有模态进入的地方:
import logo from './logo.svg'; import './App.css'; import { useState } from 'react' import Modal from './components/Modal.js'; function App() { const [isModalOpen, setIsModalOpen] = useState(false); return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <button onClick={() => setIsModalOpen(!isModalOpen)}> Click to Open Modal </button> <Modal modalState={isModalOpen} onClickEvent={() => setIsModalOpen(!isModalOpen)}> This is Modal Content! </Modal> </header> <div id="modal-container"></div> </div> ); } export default App;
在App.js
中,我导入了一个名为Modal
的组件。这是我们的 Modal 组件,它会在用户单击按钮时弹出。
每当使用setIsModalOpen()
将isModalOpen
设置为 true 时,应该出现模式。否则,它会消失。
我还有一些 CSS 来确保我们的模态确实出现在其他所有内容之上:
#modal-container { position: absolute; top: 0; left: 0; width: 100%; z-index: 9999; height: 100%; pointer-events: none; } .modal { position: absolute; top: 200px; background: white; border-radius: 4px; left: calc(50% - 100px); width: 200px; }
创建门户非常简单 - 有一个函数createPortal()
。我们没有在 React 中返回一些 DOM,而是返回Portal
。
createPortal()
接受两个参数——我们想要返回的 DOM 元素——在本例中是模态元素——以及我们想要将 DOM 元素传送到的 DOM 元素。
因此,我们的第二个参数是document.getElementById('modal-container')
,因为我们想将所有模态放入#modal-container
:
import { createPortal } from 'react-dom'; function Modal({modalState, onClickEvent}) { if(!modalState) return null; return ( createPortal( <div className="modal"> <button onClick={onClickEvent}>Close Modal</button> <div className="modal-content">Modal Content goes here</div> </div>, document.getElementById('modal-container') ) ); }; export default Modal;
尽管我们将 DOM 元素传送到了modal-container
,但它的行为仍然像一个普通的 React 子元素。由于 Portal 仍然存在于 React 树中,因此元素所在的上下文等功能仍然可以正常工作。
还应该注意的是,虽然我们在同一个文件中有modal-container
和Modal
,但你传送 DOM 元素的位置可以是 React 代码中的任何位置。
因此,您可以将其传送到 DOM 中任何位置的完全不同的子组件、元素或父组件。它非常强大和有用 - 所以要明智地使用它。
让我们回顾一下我们的App.js
HTML:
<!-- .... --> <button onClick={() => setIsModalOpen(!isModalOpen)}> Click to Open Modal </button> <Modal modalState={isModalOpen} onClickEvent={() => setIsModalOpen(!isModalOpen)}> This is Modal Content! </Modal> </header> <div id="modal-container"></div>
现在,即使Modal
位于我们的标题中,只要我们使用按钮打开 modal,它也会出现在#modal-container
中:
门户是 React 中一个非常强大的工具。它们是解决基于组件的系统的主要问题的有用方法 - 传输某些元素高于其他所有元素。
因此,我希望你喜欢这个 React 门户指南。如果您正在学习 React,我建议您先掌握 Javascript - 您可以使用我的完整Javascript 手册来完成。
祝你有美好的一天。