对于需要使用弹出层的需求 ,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. P95、P99.9百分位数值——服务响应时间的重要衡量指标

    前段时间,在对系统进行改版后,经常会有用户投诉说页面响应较慢,我们看了看监控数据,发现从接口响应时间的平均值来看在500ms左右,也算符合要求,不至于像用户说的那么慢,岁很费解,后来观察其它的一些指标 ...

  2. SpringBoot启动方式,Spring Boot 定义系统启动任务

    SpringBoot启动方式,Spring Boot 定义系统启动任务 SpringBoot启动方式 1.1 方法一 1.2 方法二 1.2.1 start.sh 1.2.2 stop.sh 1.2. ...

  3. Postman 的 Post 请求方式的四种类型的数据

    Postman 的 Post 请求方式的四种类型的数据 1. form-data 2. x-www-form-urlencoded 3. raw 4. binary 1. form-data 就是 H ...

  4. Java 8教程(知识内容详细,快速学习Java 8)

    允许在接口中有默认方法实现 Lambda表达式 函数式接口 方法和构造函数引用 Lambda的范围 内置函数式接口 Predicates Functions Suppliers Consumers C ...

  5. Kafka踩坑填坑记录

    Kafka踩坑填坑记录 一.kafka通过Java客户端,消费者无法接收消息,生产者发送失败消息 二. 一.kafka通过Java客户端,消费者无法接收消息,生产者发送失败消息 在虚拟机上,搭建了3台 ...

  6. java判断是否为整数

    /** * 判断是否为整数 * * @param str 传入的字符串 * @return 是整数返回true,否则返回false */ public static boolean isInteger ...

  7. 39.NFS(网络文件系统)

    要共享文件的主机都是Linux系统时推荐在客户端部署NFS 服务来共享文件. NFS(网络文件系统)服务可以将远程Linux 系统上的文件共享资源挂载到本地主机的目录上,从而使得本地主机(Linux ...

  8. 4. DHCP配置(Windows2012)

    1.点击服务器管理器 2.选择添加角色和功能 3. 按照添加角色和功能向导来添加 保持默认,下一步 保持默认,下一步 保持默认,下一步 勾选DHCP服务器,在弹出的小窗点击添加功能. 保持默认,下一步 ...

  9. Linux 防火墙相关操作

    目录 1.查看防火墙状态 2.部署防火墙 3.常用操作 4.其他操作 1.查看防火墙状态 systemctl status firewalld 绿字部分 Active:active(running) ...

  10. django开发东京买菜,全栈项目,前端vue,带手机GPS精准定位,带发票系统,带快递系统,带微信/支付宝/花呗/银行卡支付/带手机号一键登陆,等等

    因为博客园不能发视频,所以,完整的视频,开发文档,源码,请向博主索取 完整视频+开发文档+源码,duanshuiLu.com下载 vue+django手机购物商城APP,带支付,带GPS精准定位用户, ...