Portal createPortal()方法
React元素中的子组件,在DOM中,也会是其父组件对应DOM的后代元素。
但是,在有些场景下如果将子组件直接渲染为父组件的后代,在网页显示时会出现一些问题。
比如,需要在React中添加一个会盖住其他元素的Backdrop组件,Backdrop显示后,页面中所有的元素都会被遮盖。
很显然这里需要用到定位,但是如果将遮罩层直接在当前组件中渲染的话,遮罩层会成为当前组件的后代元素。
如果此时,当前元素后边的兄弟元素中有开启定位的情况出现,且层级不低于当前元素时,便会出现盖住遮罩层的情况。
上例代码中,App组件中引入了两个Box组件,一个绿色,一个橙色。
绿色组件中引入了Backdrop组件,Backdrop组件是一个遮罩层,可以在覆盖住整个网页。
现在三个组件的关系是,绿色Box是橙色Box的兄弟元素,Backdrop是绿色Box的子元素。
如果Box组件没有开启定位,遮罩层可以正常显示覆盖整个页面。
Backdrop能够盖住页面
但是如果为Box开启定位,并设置层级会出现什么情况呢?
现在修改Box组件,开启相对定位,并设置了z-index为1,结果页面变成了这个样子:
和上图对比,显然橙色的box没有被盖住,这是为什么呢?首先我们来看看他们的结构:
<App>
<绿色Box>
<遮罩/>
</绿色Box>
<橙色Box/>
</App>
绿色Box和橙色Box都开启了定位,且z-index相同都为1,但是由于橙色在后边,所以实际层级是高于绿色的。
由于绿色是遮罩层的父元素,所以即使遮罩的层级是9999也依然盖不住橙色。
问题出在了哪?遮罩层的作用,是用来盖住其他元素的,它本就不该作为Box的子元素出现,作为子元素了,就难免会出现类似问题。所以我们需要在Box中使用遮罩,但是又不能使他成为Box的子元素。怎么办呢?React为我们提供了一个“传送门”可以将元素传送到指定的位置上。
通过ReactDOM中的
createPortal()
方法,可以在渲染元素时将元素渲染到网页中的指定位置。这个方法就和他的名字一样,给React元素开启了一个传送门,让它可以去到它应该去的地方。
Portal的用法
- 在index.html中添加一个新的元素
-
在组件中中通过
ReactDOM.createPortal()
将元素渲染到新建的元素中 -
需使用
from 'react-dom';
来使用
ReactDOM.createPortal
不然报错
在index.html中添加新元素:
修改Backdrop组件:
如此一来,我们虽然是在Box中引入了Backdrop,但是由于在Backdrop中开启了“传送门”,
Backdrop就会直接渲染到index网页中id为backdrop的div中,这样一来上边的问题就解决了