React Portal 亮了🔥
最近我接触到了 Reacts 的 createPortal API,它简直太棒了。
让我分享一下我的经验吧!
作为一名专业的Ember 开发者,我对 React 的热爱从未消退。React 以其面向组件的架构提升了生产力,确保了代码的稳定性,并拥有强大的社区支持。
我不想让您(可能很多 Web 开发人员)每天都会听到这类事情,让您感到厌烦。
我认为,是时候让我们亲手研究一下Portal 了🔥
“门户提供了一种一流的方法,将子项渲染到存在于父组件 DOM 层次结构之外的 DOM 节点中”
一般来说,世界上并不是每个人都能一眼看懂官方文档的定义!至少我不行!(开个玩笑,Reacts 关于 Portal 的文档对初学者更友好,去看看吧)
所以我决定采取一种实用的方法:
正如定义中所述,Portals 提供了一种在 DOM 中的其他位置(不在同一层次结构中)渲染反应组件的子组件的方法!
当我意识到这一点时,我心中只剩下疑问。
天哪,事件冒泡怎么办?还有很多……
作为一名专业的 Ember 开发人员,我使用过Ember Wormhole,它是一个插件,可能可以完成与 Ember 中的 Portals 类似的工作。
我继续深入研究 Portal。其中一件事就是它在模态对话框中的用例。
我使用 bootstrap 构建了一个模态组件(覆盖了一些 bootstrap 样式),类似于这个👇
//Modal.js
import React from "react";
import ReactDOM from "react-dom";
export default class Modal extends React.Component {
onClose = e => {
this.props.onClose && this.props.onClose(e);
};
render() {
let modal = (<div
class="modal fade"
id="exampleModalCenter"
>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">
Modal title
</h5>
<button
type="button"
class="close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">...</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
>
Close
</button>
<button type="button" class="btn btn-primary">
Save changes
</button>
</div>
</div>
</div>
</div>
);
return (modal);
}
}
我把它渲染为 App 👇 的一个子类
//App.js
import React from "react";
import Modal from "./Modal-Compo";
export default class App extends React.Component {
onClose = e => {
this.props.onClose && this.props.onClose(e);
};
render() {
let alignCenter = {
display: "flex",
alignItems: "center",
justifyCenter: "center",
height: "200px",
overflow: "hidden",
width: "50%",
margin: "auto",
marginTop: "10%"
};
return (
<div style={alignCenter}>
<p style={{ height: "100%", margin: "0" }}>
//some random 100 lines
</p>
<Modal onClose={this.onClose}/>
</div>
)
}
}
Atlast 在根元素中渲染了 App 组件 👇
//Index.js
import React from "react";
import ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "jquery/dist/jquery.min.js";
import "bootstrap/dist/js/bootstrap.min.js";
import App from "./components/App";
import "./styles.css";
function WhatAreModals() {
return (
<div style={{ height: "100vh" }} className="App">
<App />
<button
type="button"
className="btn btn-primary"
data-toggle="modal"
data-target="#exampleModalCenter"
>
Launch demo modal
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<WhatAreModals />, rootElement);
我的原型终于准备好了😄
当我点击启动演示模式 CTA 时,发生了这种情况(哎呀)😕
罪魁祸首是样式为'overflow:hidden' 的App 组件,因为在我们的例子中,Modal 组件被渲染为 App 的子组件,而 App 的 overflow 是隐藏的,所以我们的 Modal 永远不会出现😩
这就是救生门户发挥作用的地方🔥
我刚刚对我的 Modal 组件和 index.html 做了一些调整(为要呈现的 Modal 创建了另一个根元素)
//index.html
<div id="root"></div>
<div id="modal-root"></div>
在 Portal 中渲染 Modal,通过实现createPortal更改返回语句
//Modal.js
ReactDOM.createPortal(modal, document.getElementById("modal-root"));
它运行得很顺畅,
通过将 Modal 组件从容器和层次结构中分离出来,问题得到了解决。
但突然间我陷入了困惑,因为层次结构被破坏了,我怀疑是否会发生事件冒泡?(我想,很多人会质疑这一点!)。
我继续深入挖掘😁
原生 DOM 快照:
反应DOM:
最后,看到这个我很满意,可能很多人都会满意😌
从快照中,我们知道 Reacts 的虚拟 DOM 中的层次结构没有改变,因此事件冒泡会很容易发生。
当父组件具有overflow: hidden或z-index 样式,但需要子组件在视觉上“突破”其容器时,可以广泛使用 Portal。例如,对话框、悬停卡片和工具提示。
我觉得这篇文章会让您对 Reacts 的 createPortal API 感到满意,如果是的话,请随时与您的同事 Web 开发人员分享。
鏂囩珷鏉ユ簮锛�https://dev.to/theaswathprabhu/portals-are-lit-31l8