对于需要使用弹出层的需求 ,Portal可以说是提供了一种完美的解决方案。相比于React Native中的实现更多的使用Modal或者绝对定位,Portal实在是简易友好得多。

场景

对话框,确认提示框,悬浮窗这些组件,一般都要做一个比当前视图层层级更高的View,但是现有的方案都很难跳出父容器的约束。如何破除这个约束?

Portal提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案

子节点可以被渲染到父组件之外的DOM,这不就是解除了这个约束了吗?

Portal:传送门。steam上有一款名为 Portal2 的游戏,互相利用传送门进行位移的配合闯关游戏,传送的含义和这里颇为相似,不过这里是“传送”组件。

使用和效果

普通的 render 方法就是将组件内的元素挂载到最近的DOM节点中。而 Portal 则通过一个API,将元素挂载到任意有效的DOM节点上。

ReactDOM.createPortal( children,container,key? )

具体参数类型如下:

现在开始在代码中使用:

  1. public目录下的index.html文件中,设置<div id="modal"></div>。后面 React 元素会被放到modal这个div里,这个DOM元素就是container

      <div id="root"></div>
    <div id="modal"></div>
  2. 对该 API 做简单封装,构建Modal组件。因为Portal API是读children子组件的,所以Portal肯定是作为容器来用。

    (这里直接操作操作了children,你也可以像Portal文档一样,在其中多加一个div层级隔离)

    const modalDivElement = document.getElementById("modal");
    
    export default function Modal({ children }) {
    return ReactDOM.createPortal(children, modalDivElement);
    }

    使用createPortal API,Modal 组件中的子元素children会被渲染到modalDivElement中,而不管你的Modal在何处使用。

  3. 使用Modal组件。在红色背景div中嵌入了Modal, Modal中只有一个div字符串zhangsan

    export default function App() {
    return (
    <div style={{ backgroundColor: "#a00", width: `200px`, height: `100px` }}>
    <Modal>
    <div>zhangsan</div>
    </Modal>
    </div>
    );
    }

    现在来看看效果:

    如果没有Modal层级,zhanghsan是应该在红色区域里面的。但是为什么加了Modal就在外面了?这时检查渲染结构,秘密就在这里:

    可以看到,Modal中的元素被渲染到了id="modal"的这个div里。来回顾一下发生了什么,我们的代码组件结构是这样:

          <div id="root">
    <div style={{ backgroundColor: "#a00", width: `200px`, height: `100px` }}>
    <Modal>
    <div>zhangsan</div>
    </Modal>
    </div>
    </div>
    <div id="modal"></div>

    但是实际的渲染结构却是这样(观察其中Modal子元素的变化):

          <div id="root">
    <div style={{ backgroundColor: "#a00", width: `200px`, height: `100px` }</div>
    </div>
    <div id="modal">
    <div>zhangsan</div>
    </div>

    实际渲染结构和代码结构并不一致了 ,是因为Modal中的Portal将子元素方法放到了指定的container中。子元素被跨层级渲染,就像被传送过去一样,这便是Portal

制作一个 Modal 弹出框组件

上面只是演示了Portal传送子组件的效果,如果要做到弹出蒙层的效果,只需要在需要传送的children子元素上添加一个div包裹并添加样式,如果弹出层样式一致,可以直接Modal组件中,当然也可以在具体的children中实现并自定义样式。

实例:

例子代码:

export default function App() {
const [isShow, setIsShow] = useState(false);
function click(e) {
console.info("e", e);
setIsShow(!isShow);
}
return (
<div
style={{
backgroundColor: "#a00",
width: `200px`,
height: `100px`,
}}
onClick={click}
>
{isShow && (
<Modal>
<span>zhangsan</span>
</Modal>
)}
</div>
);
}

Modal组件:

const modalDivElement = document.getElementById("modal");

export default function Modal({ children }) {
const modalContent = (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: `rgba(0, 0, 0, 0.5)`,
}}
>
{children}
</div>
);
return ReactDOM.createPortal(modalContent, modalDivElement);
}

如果Modal交互和内容切换较多,可以进一步封装后通过ref命令式的调用,动态传入Modal和子组件切换。

Portal 事件冒泡

Portal中的事件冒泡是遵从React结构的,并不是实际渲染的DOM元素结构,也就是说上面的root节点可以获取到modal中冒泡出来的事件。

而,上面的页面中的click事件,可以获取点击红色区域触发Modal的事件,也能获取到Modal内部的点击span的事件:

这样,Modal中的交互控制并没有脱离当前的页面或组件,和没有使用Portal时的事件表现一致。

React Portal - 弹出层的优秀解决方案的更多相关文章

  1. layer弹出层不居中解决方案

    layer弹出层不居中解决方案 代码头中加入以下代码即可 <!doctype html>

  2. layer弹出层不居中解决方案,layer提示不屏幕居中解决方法,layer弹窗不居中解决方案

    layer弹出层不居中解决方案,layer提示不屏幕居中解决方法,layer弹窗不居中解决方案 >>>>>>>>>>>>> ...

  3. layer弹出层不居中解决方案,仅显示遮罩,没有弹窗

    问题:项目中layer询问层的弹窗仅显示遮罩层,并不显示弹窗…… 原因:图片太多将layer弹窗挤出屏幕下方,看不见了…… 解决方案:让layer的弹出层居中显示 一.问题描述 用layer做操作结果 ...

  4. layer弹出层不居中解决方案(转)

    @感谢参考文章 原文内容: 一.问题描述 用layer做操作结果提示时,发现如果页面超出屏幕的高度时,弹出的提示不是屏幕居中,而是在页面高度的中间,如果一个页面的高度比较大,就看不到提示了. 还有一种 ...

  5. react学习之弹出层

    react的弹出层不同于以往的DOM编程,我们知道,在DOM中,弹出层事件绑定在对应的节点上即可,但是在react中,往往只能实现父子之间的传递控制,显然,弹出层的层级不符合此关系. 在这里我们需要使 ...

  6. layer 弹出层 不居中

    layer弹出层不居中解决方案 代码头中加入以下代码即可 <!doctype html>

  7. React native 的弹出层(输入)效果

    /*弹出层测试*/ import React,{Component} from 'react'; import { StyleSheet, View, Image, Text, TouchableOp ...

  8. 利用React/anu编写一个弹出层

    本文将一步步介绍如何使用React或anu创建 一个弹出层. React时代,代码都是要经过编译的,我们很多时间都耗在babel与webpack上.因此本文也介绍如何玩webpack与babel. 我 ...

  9. react 点击空白处隐藏弹出层

    点击空白处隐藏弹出层的原理是:在 document 上绑定事件来隐藏弹出层,这样点击任何元素的时候都会冒泡到 document 上,都会执行隐藏弹出层的功能.然后我们在不需要隐藏弹出层的元素上阻止冒泡 ...

随机推荐

  1. Java关键字及作用解释

    访问控制 1) private 私有的 private 关键字是访问控制修饰符,可以应用于类.方法或字段(在类中声明的变量). 只能在声明 private(内部)类.方法或字段的类中引用这些类.方法或 ...

  2. JQuery——相关练习

    ####JQuery的基本语法 <!--导入JQuery文件--> <script src="js/jquery-3.1.1.min.js"> /*带min ...

  3. Phoenix表和索引分区优化方法

    Phoenix表和索引分区,基本优化方法 优化方法 1. SALT_BUCKETS RowKey SALT_BUCKETS 分区 2. Pre-split RowKey分区 3. 分列族 4. 使用压 ...

  4. 在 .NET Core Logging中使用 Trace和TraceSource

    本文介绍了在.NET Core中如何在组件设计中使用Trace和TraceSource. 在以下方面会提供一些帮助: 1.你已经为.NET Framework和.NET Core / .NET Sta ...

  5. thymeleaf第一篇:什么是-->为什么要使用-->有啥好处这玩意

    Thymeleaf3.0版本官方地址 1 Introducing Thymeleaf Thymeleaf 是一个跟 Velocity.FreeMarker 类似的模板引擎,它可以完全替代 JSP . ...

  6. Pytest(5)美化插件进度条pytest-sugar

    前言 在我们进行自动化测试的时候,用例往往是成百上千,执行的时间是几十分钟或者是小时级别.有时,我们在调试那么多用例的时候,不知道执行到什么程度了,而pytest-sugar插件能很好解决我们的痛点. ...

  7. CPU的后记,程序员的未来之计

    ​ 渔家傲 塞下秋来风景异,衡阳雁去无留意.四面边声连角起,千嶂里,长烟落日孤城闭. 浊酒一杯家万里,燕然未勒归无计.羌管悠悠霜满地.人不寐,将军白发征夫泪. 作者:良知犹存 转载授权以及围观:欢迎添 ...

  8. Hive创建HBase,ES外部表

    1.创建HBase外部表 CREATE EXTERNAL TABLE `ods_women`( `rowkey` string COMMENT 'from deserializer', `articl ...

  9. AtCoder Beginner Contest 176 E - Bomber (思维)

    题意:有一张\(H\)x\(W\)的图,给你\(M\)个目标的位置,你可以在图中放置一枚炸弹,炸弹可以摧毁所在的那一行和一列,问最多可以摧毁多少目标. 题解:首先我们记录某一行和某一列目标最多的数目, ...

  10. 牛客编程巅峰赛S2第7场 - 钻石&王者 A.牛牛的独特子序列 (字符串,二分)

    题意:给你一个字符串,找出一个类似为\(aaabbbccc\)这样的由连续的\(abc\)构成的子序列,其中\(|a|=|b|=|c|\),问字符串中能构造出的子序列的最大长度. 题解:这题刚开始一直 ...