本文共 3578 字,大约阅读时间需要 11 分钟。
这篇文章说说关于Protals
2个点:
一、关于react
的Portal
插槽。根据官网的说法:
一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框。就是这种需要在某个组件中使用,但是视图上需要在全局的范围。
Portal
提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
先来看下Portal
的用法:第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。
ReactDOM.createPortal(child, container) // child即子组件中的内容,如``组件中的` test<test`
由于是在我现有测试项目的基础上改造,所以和官网例子稍微有点不同。不过是可以对照着看的:
App.js// 这是app根组件,Routers渲染home页。也就是说,我们即将要渲染的弹窗会在id为`box`的`div`中。和渲染出的home平级。import Routers from './router/router';class App extends Component { render () { return () }}export default App;
home.js
/* eslint-disable */import React from "react";import Header from '../../component/header/header.js';import Footer from '../../component/footer/footer';import Sidebar from '../../component/sidebar/sidebar';import './home.scss'const modalRoot = document.getElementById('box'); // 获取`id`为`box`的`dom`// 弹窗组件class Modal extends React.Component { constructor(props) { super(props); this.el = document.createElement('div'); } componentDidMount() { modalRoot.appendChild(this.el); } componentWillUnmount() { modalRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } }// 父组件class Home extends Component { constructor(props) { super(props) this.state = { showModal: false, } } handleShow = () => { this.setState({ showModal: true, }) } handleHide = () => { this.setState({ showModal: false, }) } getModal = () => { console.log('这是Modal冒泡的事件') } render () { const modal = this.state.showModal ? () : null; return ( With a portal, we can render content into a different part of the DOM, as if it were any other React child.This is being rendered inside the #modal-container div.) }}export default HomeThis div has overflow: hidden. { modal}
home.scss
.app { height: 10em; width: 10em; background: lightblue; overflow: hidden;} .modal { background-color: rgba(0,0,0,0.5); position: fixed; height: 100%; width: 100%; top: 0; left: 0; display: flex; align-items: center; justify-content: center;}
代码逻辑: 在App
根组件,放置了一个id为box
的dom
,同级放置了一个渲染home
页面的Router
组件。在home
组件中渲染modal
。
modal
是home
组件的子节点。当showModal
为false
的时候,不进行渲染。为true
时,渲染Modal
组件。Modal
组件先是创建了一个div
并且插入到id为box
的div
中。利用ReactDOM.createPortal
将Modal
中的节点渲染到创建的div
中。 渲染结果
下面是注释掉modalRoot.removeChild(this.el);
这里
建议:项目中实际使用时,可以将Modal
组件最终渲染在父组件Home
之外的App
组件id为box
的dom上。Modal
单独写一个文件。直接引用就可以。最大限度的复用可以降低冗余。 代码中Modal
组件,在componentDidMount
和componentWillUnmount
中分别添加和移除了dom。可以试一下,如果不移除,那么每渲染一次Modal
节点中就会多出一对div
节点。这样不符合我们优化的思想。
二、Protals
事件冒泡。上面的代码在Home
组件下className
为app
的dom上添加了getModal
事件。这时候我们运行程序,点击Hide modal
按钮,打开控制台,会发现打印出这是Modal冒泡的事件
。虽然Modal
最终是挂载到box
下面。但从Modal
中冒泡上来的事件依然能被{modal}
的所有parents
捕捉到。
转载地址:http://xnzsi.baihongyu.com/