对于需要使用弹出层的需求 ,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. poj 2752Seek the Name, Seek the Fame

    Seek the Name, Seek the Fame Time Limit: 2000MS   Memory Limit: 65536KB   64bit IO Format: %I64d &am ...

  2. RocketMQ 常用消息类型

    文章首发于公众号<程序员果果> 地址 : https://mp.weixin.qq.com/s/dYqGd9zi2mNelsNNLIribg 消息发送示例 导入依赖: <depend ...

  3. ResponseEntity和@ResponseBody以及@ResponseStatus区别

    看的迷迷糊糊的 https://www.jdon.com/springboot/responseentity.html

  4. 分布式缓存 — Docker

    Docker 是一个开源项目,它基于 Google 公司推出的 Go 语言实现. 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护. Doc ...

  5. Spark使用Java、Scala 读取mysql、json、csv数据以及写入操作

    Spark使用Java读取mysql数据和保存数据到mysql 一.pom.xml 二.spark代码 2.1 Java方式 2.2 Scala方式 三.写入数据到mysql中 四.DataFrame ...

  6. hadoop知识点总结(二)hdfs分布式文件系统

    1, hdfs设计:减少硬件错误的危害,流式数据访问,大规模数据集,简单的一致性模型 2,特点: 1)移动计算的代价比移动数据的代价低 在异构的软硬件平台间的可移植性 2)局限性 不适合低延迟性数据访 ...

  7. Spring boot 使用Redis 消息队列

    package com.loan.msg.config; import com.loan.msg.service.MessageReceiver; import org.springframework ...

  8. 常用的正则表达式@java后台

    package Regex; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @作者 Goofy * @邮件 ...

  9. 19.损坏磁盘阵列及修复&磁盘阵列+备份盘

    1.在确认有一块物理硬盘设备出现损坏而不能继续正常使用后,应该使用mdadm 命令将其移除,然后查看RAID 磁盘阵列的状态,可以发现状态已经改变. [root@Centos ~]# mdadm /d ...

  10. 2019牛客暑期多校训练营(第二场) H-Second Large Rectangle(单调栈)

    题意:给出由01组成的矩阵,求求全是1的次大子矩阵. 思路: 单调栈 全是1的最大子矩阵的变形,不能直接把所有的面积存起来然后排序取第二大的,因为次大子矩阵可能在最大子矩阵里面,比如: 1 0 0 1 ...