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 相关文章推荐
js实现的真正的iframe高度自适应(兼容IE,FF,Opera)
Mar 07 Javascript
jQuery.ajax 用户登录验证代码
Oct 29 Javascript
jQuery登陆判断简单实现代码
Apr 21 Javascript
js 实现日期灵活格式化的小例子
Jul 14 Javascript
使用jQuery插件创建常规模态窗口登陆效果
Aug 23 Javascript
HTTP 304错误的详细讲解
Nov 13 Javascript
js Dialog 去掉右上角的X关闭功能
Apr 23 Javascript
JS实现的简洁二级导航菜单雏形效果
Oct 13 Javascript
JS实现的自定义水平滚动字体插件完整实例
Jun 17 Javascript
js下载文件并修改文件名
May 08 Javascript
Vue微信公众号网页分享的示例代码
May 28 Javascript
JavaScript实现世界各地时间显示
Sep 07 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下实现农历日历的代码
2007/03/07 PHP
PHP判断浏览器、判断语言代码分享
2015/03/05 PHP
浅谈PHP中类和对象的相关函数
2017/04/26 PHP
PHP实现的数据对象映射模式详解
2019/03/20 PHP
php创建多级目录与级联删除文件的方法示例
2019/09/12 PHP
php 中的信号处理操作实例详解
2020/03/04 PHP
PHP autoload使用方法及步骤详解
2020/09/05 PHP
理解Javascript_11_constructor实现原理
2010/10/18 Javascript
Nodejs学习item【入门手上】
2016/05/05 NodeJs
ashx文件获取$.ajax()方法发送的数据
2016/05/26 Javascript
简单理解Vue条件渲染
2016/12/03 Javascript
微信小程序实现轮播图效果
2017/09/07 Javascript
Vue2 模板template的四种写法总结
2018/02/23 Javascript
使用JavaScript破解web
2018/09/28 Javascript
vue实现搜索过滤效果
2019/05/28 Javascript
模块化react-router配置方法详解
2019/06/03 Javascript
浅谈vue项目利用Hbuilder打包成APP流程,以及遇到的坑
2020/09/12 Javascript
Python实现批量修改文件名实例
2015/07/08 Python
vscode 远程调试python的方法
2017/12/01 Python
win7+Python3.5下scrapy的安装方法
2018/07/31 Python
python开启摄像头以及深度学习实现目标检测方法
2018/08/03 Python
Python绘制堆叠柱状图的实例
2019/07/09 Python
在vscode中配置python环境过程解析
2019/09/28 Python
Pandas-Cookbook 时间戳处理方式
2019/12/07 Python
Django与pyecharts结合的实例代码
2020/05/13 Python
Keras 快速解决OOM超内存的问题
2020/06/11 Python
Python自动化办公Excel模块openpyxl原理及用法解析
2020/11/05 Python
韩国著名的在线综合购物网站:Akmall
2016/08/07 全球购物
如何利用find命令查找文件
2015/02/07 面试题
入党积极分子评语
2014/05/04 职场文书
2014个人四风对照检查材料思想汇报
2014/09/18 职场文书
本科毕业答辩开场白
2015/05/27 职场文书
党员发展大会主持词
2015/07/03 职场文书
教师节联欢会主持词
2015/07/04 职场文书
银行岗位培训心得体会
2016/01/09 职场文书
windows系统安装配置nginx环境
2022/06/28 Servers