React.createPortal 及 Modal 的新实现方式

每个项目产品都要加埋点,加500行埋点是不是会占用你一两天的时间而且很容易犯错,想只用一小时准确加完这500行埋点剩下一天喝茶聊天么?来试试这520工具, 高效加埋点,目前我们公司100号前端都在用,因为很好用,所以很自然普及开来了,推荐给大家吧

http://www.520webtool.com/

自己开发所以免费,埋点越多越能节约时间,点两下埋点就加上了,还不会犯错,里面有使用视频,反正免费 😄

 

 

一、描述

一般使用 React 的组件都是挂到父组件的 this.props.children 上面,总是被最近的父组件所捕获,最终到 React 根组件上。

而 Protals 则提供了一种将组件直接挂载到直接父组件 DOM 层次之外的一类方式。

react-dom 提供的具体方法是 ReactDOM.createPortals(child, container),这个方法需要两个参数,第一个参数是需要挂载的组件实例,而第二个参数则是要挂载到的DOM节点。一般来说第一个参数可能传递的是需要挂载的 this.props.children

二、之前的 Modal 组件

以一个 Modal 弹窗举例(官网也是用的这个例子)。

正常来说,我要创建一个 Modal 组件,可以按照下面这么写:

const styles = {
  modal: {
    position: 'fixed',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(0,0,0,0.3)',
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center'
  }
}

class Modal extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div style={styles.modal}>
        {this.props.children}
      </div>
    );
  }
}

而使用的时候直接引入并且写子组件即可:

<div className="App">
        <Modal>
          <h1>Modal</h1>
        </Modal>
 </div>

最终的效果如下:

a.png

Modal 的组件实例这种实现方式也可以,这里的突破方式其实就是直接将 Modal 组件位置进行 fixed 定位。

但是更多时间如果父组件容器存在 overflow: hidden 或者存在 z-index 的时候,需要在视觉上突破父组件的容器,使用 createPortal 更好一些,因为他可以随便将组件挂到任何的 DOM 下。

三、 createProtal 改造 Modal 组件:

1、html 预留容器

在 html 中除了 div#root 之外,给 Modal 预留了一个新的 div#modal-root,:

const appRoot = document.getElementById('root');
const modalRoot = document.getElementById('modal-root');

为了突出 div#root 容器宽度高度很小,并且 overflow:hidden,给 div#root 一个样式:

#root {
  height: 10em;
  width: 10em;
  background: lightblue;
  overflow: hidden;
}

2、改造 Modal 容器

新的 Modal 容器组件内容如下:

class ModalContainer extends 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
    );
  }
}

因为需要保证 ModalContainer 始终保持在最上层,不会被其他 z-index 覆盖掉,因此需要给 div#modal-root 一个样式:

#modal-root {
  position: relative;
  z-index: 999;
}

3、Modal 组件的内容

上面只是 Modal 的容器组件,最主要的作用就是将 this.props.children 挂载到组件外部去(div#modal-root

需要创建 Modal 需要显示的内容组件:

#modal-root {
  position: relative;
  z-index: 999;
}

4、使用 Modal 容器组件和内容组件

将 ModalContent 挂载到 ModalContainer 中即可:

class App2 extends Component {
  state = {
    name: 'clickme'
  }
  componentDidMount(){
    // console.log(findDOMNode(ref.current))
  }
  clickHandle = () => {
    this.setState({
      name: 'clickme' + Date.now()
    });
  }
render() {
  return ( 
      <div className="App">
        <ModalContainer>
          <ModalContent />
        </ModalContainer>
      </div>
  );
}
}

5、效果

可以发现,即使主组件是 overflow:hidden 的,但是 modal 能够正常出现,同时,因为 div#modal-root 是 z-index: 999,因此会置于最上层。

GIF.gif

可以发现,在父组件里捕获一个来自 Portal 的事件冒泡很简单,在开发时不需要完全依赖于 Portal ,对于时间的捕获更加的灵活。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值