React如何将组件渲染到指定DOM节点详解


Posted in Javascript onSeptember 08, 2017

前言

众所周知React优点之一就是他的API特别简单。通过render 方法返回一个组件的基本结构,如同一个简单的函数,就可以得到一个可以复用的react组件。但是有时候还是会有些限制的,尤其是他的API中,不能控制组件所应该渲染到的DOM节点,这就让一些弹层组件很难控制。当父元素设置为overflow:hidden 的时候,问题就会出现了。

例如就像下面的这样:

React如何将组件渲染到指定DOM节点详解

我们实际期待的效果是这样的:

React如何将组件渲染到指定DOM节点详解

幸运的是,虽然不是很明显,但有一个相当优雅的方式来绕过这个问题。我们学到的第一个react函数是render 方法,他的函数签名是这样的:

ReactComponent render(
 ReactElement element,
 DOMElement container,
 [function callback]
)

通常情况下我们使用该方法将整个应用渲染到一个DOM节点中。好消息是该方法并不仅仅局限于此。我们可以在一个组件中,使用ReactDom.render 方法将另一个组件渲染到一个指定的DOM 元素中。作为一个组件的render 方法,其必须是纯净的(例如:不能改变state或者与DOM交互).所以我们需要在componentDidUpdate 或者 componentDidMount 中调用ReactDom.render 方法。

另外我们需要确保在父元素被卸载的时候,改组件也要被卸载掉.

整理下,我们得到下面的一个组件:

import React,{Component} from 'react';
import ReactDom from 'react-dom';
export default class RenderInBody extends Component{
 constructor(p){
  super();
 }
 componentDidMount(){//新建一个div标签并塞进body
  this.popup = document.createElement("div");
  document.body.appendChild(this.popup);
  this._renderLayer();
 }
 componentDidUpdate() {
  this._renderLayer();
 }
 componentWillUnmount(){//在组件卸载的时候,保证弹层也被卸载掉
  ReactDom.unmountComponentAtNode(this.popup);
  document.body.removeChild(this.popup);
 }
 _renderLayer(){//将弹层渲染到body下的div标签
  ReactDom.render(this.props.children, this.popup);
 }
 render(){
  return null;
 }
}

总结下就是:

在componentDidMount的时候手动向body内塞一个div标签,然后使用ReactDom.render 将组件渲染到这个div标签

当我们想把组件直接渲染到body上的时候,只需要在该组件的外面包一层RenderInBody 就可以了.

export default class Dialog extends Component{
 render(){
  return {
   <RenderInBody>i am a dialog render to body</RenderInBody>
  }
 }
}

译者增加:

将以上组件改造一下,我们就可以向指定的dom节点中渲染和卸载组件,并加上位置控制,如下:

//此组件用于在body内渲染弹层
import React,{Component} from 'react'
import ReactDom from 'react-dom';
export default class RenderInBody extends Component{
 constructor(p){
  super(p);
 }
 componentDidMount(){
  /**
  popupInfo={
   rootDom:***,//接收弹层组件的DOM节点,如document.body
   left:***,//相对位置
   top:***//位置信息
  }
  */
  let {popupInfo} = this.props; 
  this.popup = document.createElement('div');
  this.rootDom = popupInfo.rootDom;  
  this.rootDom.appendChild(this.popup);
  //we can setAttribute of the div only in this way
  this.popup.style.position='absolute';
  this.popup.style.left=popupInfo.left+'px';
  this.popup.style.top=popupInfo.top+'px';
  this._renderLayer()
 }
 componentDidUpdate() {
  this._renderLayer();
 }
 componentWillUnmount(){
  this.rootDom.removeChild(this.popup);
 }
 _renderLayer(){
  ReactDom.render(this.props.children, this.popup);
 }
 render(){
  return null;
 }
}

注:位置获取和根结点判断函数

export default (dom,classFilters)=> {
 let left = dom.offsetLeft,
  top = dom.offsetTop + dom.scrollTop,
  current = dom.offsetParent,
  rootDom = accessBodyElement(dom);//默认是body
 while (current !=null ) {
  left += current.offsetLeft;
  top += current.offsetTop;
  current = current.offsetParent;
  if (current && current.matches(classFilters)) {
   rootDom = current;
   break;
  }
 }
 return { left: left, top: top ,rootDom:rootDom};
}
/***
1. dom:为响应弹层的dom节点,或者到该dom的位置后,可以做位置的微调,让弹层位置更佳合适
*
2. classFilters:需要接收弹层组件的DOM节点的筛选类名
/

原文地址

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JQuery获取浏览器窗口内容部分高度的代码
Feb 24 Javascript
nullJavascript中创建对象的五种方法实例
May 07 Javascript
js闭包的用途详解
Nov 09 Javascript
JavaScript让Textarea支持tab按键的方法
Jun 26 Javascript
创建简单的node服务器实例(分享)
Jun 23 Javascript
Vue自定义指令详解
Jul 28 Javascript
谈谈JS中的!!
Dec 07 Javascript
微信小程序swiper组件用法实例分析【附源码下载】
Dec 07 Javascript
js实现关闭网页出现是否离开提示
Dec 07 Javascript
微信小程序实现滴滴导航tab切换效果
Jul 24 Javascript
JavaScript深入V8引擎以及编写优化代码的5个技巧
Jun 24 Javascript
解决Vue的项目使用Element ui 走马灯无法实现的问题
Aug 03 Javascript
javascript获取指定区间范围随机数的方法
Sep 08 #Javascript
原生js实现简单的模态框示例
Sep 08 #Javascript
javascript 面向对象实战思想分享
Sep 07 #Javascript
vue 封装自定义组件之tabal列表编辑单元格组件实例代码
Sep 07 #Javascript
用js实现before和after伪类的样式修改的示例代码
Sep 07 #Javascript
vue使用drag与drop实现拖拽的示例代码
Sep 07 #Javascript
SelectPage v2.4 发布新增纯下拉列表和关闭分页功能
Sep 07 #Javascript
You might like
[原创]PHP正则删除html代码中a标签并保留标签内容的方法
2017/05/23 PHP
PHP大文件分片上传的实现方法
2018/10/28 PHP
JQuery最佳实践之精妙的自定义事件
2010/08/11 Javascript
javascript实现点击商品列表checkbox实时统计金额的方法
2015/05/15 Javascript
纯js代码实现未知宽高的元素在指定元素中垂直水平居中显示
2015/09/12 Javascript
JavaScript前端开发之实现二进制读写操作
2015/11/04 Javascript
AngularJS中实现动画效果的方法
2016/07/28 Javascript
vue实现动态数据绑定
2017/04/28 Javascript
NodeJS自定义模块写法(详解)
2017/06/27 NodeJs
JS实现左边列表移到到右边列表功能
2018/03/28 Javascript
JavaScript设计模式之装饰者模式定义与应用示例
2018/07/25 Javascript
基于vue2.0的活动倒计时组件countdown(附源码下载)
2018/10/09 Javascript
vue模仿网易云音乐的单页面应用
2019/04/24 Javascript
Python中强大的命令行库click入门教程
2016/12/26 Python
Python Socket实现简单TCP Server/client功能示例
2017/08/05 Python
python 通过可变参数计算n个数的乘积方法
2019/06/13 Python
Django Admin后台添加数据库视图过程解析
2020/04/01 Python
学习python需要有编程基础吗
2020/06/02 Python
python使用建议技巧分享(三)
2020/08/18 Python
解释i节点在文件系统中的作用
2013/11/26 面试题
初中地理教学反思
2014/01/11 职场文书
毕业生自荐书
2014/02/03 职场文书
医学生个人求职信范文
2014/02/07 职场文书
幼儿园家长评语
2014/02/10 职场文书
小小的船教学反思
2014/02/21 职场文书
工作决心书
2014/03/11 职场文书
洗车工岗位职责
2014/03/15 职场文书
财产公证书样本
2014/04/04 职场文书
应急处置方案
2014/06/16 职场文书
单位租房协议书范本
2014/12/04 职场文书
先进集体事迹材料范文
2014/12/25 职场文书
试用期自我评价范文
2015/03/10 职场文书
2019通用版劳动合同范本!
2019/07/11 职场文书
python 破解加密zip文件的密码
2021/04/22 Python
详解CSS故障艺术
2021/05/25 HTML / CSS
Redis分布式锁Redlock的实现
2021/08/07 Redis