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代码,粗糙版
Nov 04 Javascript
artdialog的图片/标题以及关闭按钮不显示的解决方法
Jun 27 Javascript
HTML Color Picker(js拾色器效果)
Aug 27 Javascript
Javascript中call和apply函数的比较和使用实例
Feb 03 Javascript
JS onkeypress兼容性写法详解
Apr 27 Javascript
AngularJS基础 ng-cut 指令介绍及简单示例
Aug 01 Javascript
基于jQuery实现发送短信验证码后的倒计时功能(无视页面关闭)
Sep 02 Javascript
jQuery插件select2利用ajax高效查询大数据列表(可搜索、可分页)
May 19 jQuery
jQuery仿移动端支付宝键盘的实现代码
Aug 15 jQuery
小程序获取当前位置加搜索附近热门小区及商区的方法
Apr 08 Javascript
node.js 基于cheerio的爬虫工具的实现(需要登录权限的爬虫工具)
Apr 10 Javascript
JavaScript(js)处理的HTML事件、键盘事件、鼠标事件简单示例
Nov 19 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下通过exec获得计算机的唯一标识[CPU,网卡 MAC地址]
2011/06/09 PHP
有道搜索和IP138的IP的API接口(PHP应用)
2012/11/29 PHP
PHP编程函数安全篇
2013/01/08 PHP
PHP的构造方法,析构方法和this关键字详细介绍
2013/10/22 PHP
PHP微信开发之有道翻译
2016/06/23 PHP
PHP实现的mysql主从数据库状态检测功能示例
2017/07/20 PHP
laravel 5.3 单用户登录简单实现方法
2019/10/14 PHP
原生js和jquery实现图片轮播特效
2015/04/23 Javascript
BootStrap注意事项小结(五)表单
2017/03/10 Javascript
JS实现图片旋转动画效果封装与使用示例
2018/07/09 Javascript
jQuery操作cookie的示例代码
2019/06/05 jQuery
vue.js实现备忘录demo
2019/06/26 Javascript
Vue中函数防抖节流的理解及应用实现
2020/04/24 Javascript
vue prop传值类型检验方式
2020/07/30 Javascript
python使用xmlrpc实例讲解
2013/12/17 Python
理解生产者消费者模型及在Python编程中的运用实例
2016/06/26 Python
python基于pyDes库实现des加密的方法
2017/04/29 Python
选择Python写网络爬虫的优势和理由
2019/07/07 Python
python每天定时运行某程序代码
2019/08/16 Python
如何在 Django 模板中输出 &quot;{{&quot;
2020/01/24 Python
python集合删除多种方法详解
2020/02/10 Python
基于python模拟TCP3次握手连接及发送数据
2020/11/06 Python
Python实现Appium端口检测与释放的实现
2020/12/31 Python
纯css3显示隐藏一个div特效的具体实现
2014/02/10 HTML / CSS
HTML5离线缓存Manifest是什么
2016/03/09 HTML / CSS
美国内衣品牌:Leonisa
2016/08/14 全球购物
实习医生自我评价
2013/09/22 职场文书
一份报关员的职业规划范文
2014/01/08 职场文书
打架检讨书500字
2014/01/29 职场文书
网站客服岗位职责
2014/04/05 职场文书
新学期开学演讲稿
2014/05/24 职场文书
节能环保口号
2014/06/12 职场文书
文明单位申报材料
2014/12/23 职场文书
寻找成龙观后感
2015/06/12 职场文书
mysql事务隔离级别详情
2021/10/24 MySQL
 python中的元类metaclass详情
2022/05/30 Python