React的Portals的用法

在线演示https://myp00yr1xx.codesandbox.io/react-portal
在线代码https://codesandbox.io/embed/myp00yr1xx?fontsize=14
不知道大家想过这样一个问题没有,我们创建了一个子组件后,要把它放到指定的dom元素下面,该怎么办?
ReactDom提供了这样一个api

// child可以是ReactElement, Arrays, fragments, Portals, String, numbers,
// Booleans, null, ...
// container是dom元素
ReactDOM.createPortal(child, container)

下面代码是创建一个Foo组件(表现为200*200的div),放到body的中央位置。

import React from "react";
import ReactDom from "react-dom";

export default class extends React.Component {
  div = document.createElement("div");

  componentWillUnmount() {
    document.body.removeChild(this.div);
  }

  componentDidMount() {
    document.body.appendChild(this.div);
  }

  render() {
    return ReactDom.createPortal(<Foo />, this.div);
  }
}

const styles = {
  position: "absolute",
  top: "50%",
  left: "50%",
  transform: "translate(-50%, -50%)",
  width: 200,
  height: 200,
  zIndex: 100,
  background: "rgba(222,222,222,0.4)",
  boxShadow: "5px 5px 5px 5px gray"
};
const Foo = () => {
  return <div style={styles}>Portals的使用</div>;
};

Portals的事件传递

我们改造下上面的代码:

import React from "react";
import ReactDom from "react-dom";

class App extends React.Component {
  div = document.createElement("div");

  componentWillUnmount() {
    document.body.removeChild(this.div);
  }

  componentDidMount() {
    document.body.appendChild(this.div);
  }

  render() {
    return ReactDom.createPortal(<Foo />, this.div);
  }
}

const styles = {
  position: "absolute",
  top: "50%",
  left: "50%",
  transform: "translate(-50%, -50%)",
  width: 200,
  height: 200,
  zIndex: 100,
  background: "rgba(222,222,222,0.4)",
  boxShadow: "5px 5px 5px 5px gray"
};
const Foo = () => {
  return (
    <div onClick={() => console.info("触发点击事件")} style={styles}>
      Portals的使用
    </div>
  );
};

export default () => (
  <div
    style={{ border: "1px solid red" }}
    onClick={() => console.info("点击事件冒泡到其React的虚拟DOM父节点")}
  >
    <p>React虚拟DOM父节点</p>
    <App />
  </div>
);

虽然我们通过Dom操作,把它移到了document.body下,与React 的虚拟Dom结构不一致,但是React 的虚拟Dom结构并未发生变化,父子关系仍然存在。这就导致,事件的传递依然有效,在Foo组件触发的click事件,依然会传递到App组件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值