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 相关文章推荐
date.parse在IE和FF中的区别
Jul 29 Javascript
开发 Internet Explorer 右键功能表(ContextMenu)
Jul 03 Javascript
页面载入结束自动调用js函数示例
Sep 23 Javascript
JavaScript截取字符串的2个函数介绍
Aug 27 Javascript
jQuery弹出层后禁用底部滚动条(移动端关闭回到原位置)
Aug 29 Javascript
js中DOM三级列表(代码分享)
Mar 20 Javascript
IScroll那些事_当内容不足时下拉刷新的解决方法
Jul 18 Javascript
React Native中的RefreshContorl下拉刷新使用
Oct 09 Javascript
js实现鼠标单击Tab表单切换效果
May 16 Javascript
mpvue写一个CPASS小程序的示例
Sep 04 Javascript
详解项目升级到vue-cli3的正确姿势
Jan 28 Javascript
vue 使用鼠标滚动加载数据的例子
Oct 31 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函数获取当前运行的环境 来进行判断执行逻辑(小技巧)
2013/06/25 PHP
浅谈PHP解析URL函数parse_url和parse_str
2014/11/11 PHP
php命令行(cli)下执行PHP脚本文件的相对路径的问题解决方法
2015/05/25 PHP
javascript cookie操作类的实现代码小结附使用方法
2010/06/02 Javascript
麻雀虽小五脏俱全 Dojo自定义控件应用
2010/09/04 Javascript
JavaScript高级程序设计 错误处理与调试学习笔记
2011/09/10 Javascript
jquery foreach使用示例
2013/09/12 Javascript
原生js实现日期联动
2015/01/12 Javascript
jQuery浏览器CSS3特写兼容实例
2015/01/19 Javascript
jQuery实现点击后标记当前菜单位置(背景高亮菜单)效果
2015/08/22 Javascript
JavaScript对HTML DOM使用EventListener进行操作
2015/10/21 Javascript
微信小程序page的生命周期和音频播放及监听实例详解
2017/04/07 Javascript
webpack配置sass模块的加载的方法
2017/07/30 Javascript
Vue 仿QQ左滑删除组件功能
2018/03/12 Javascript
微信小程序踩坑记录之解决tabBar.list[3].selectedIconPath大小超过40kb
2018/07/04 Javascript
vuejs使用axios异步访问时用get和post的实例讲解
2018/08/09 Javascript
vue将毫秒数转化为正常日期格式的实例
2018/09/16 Javascript
Vue中el-form标签中的自定义el-select下拉框标签功能
2020/04/20 Javascript
Vue 实例中使用$refs的注意事项
2021/01/29 Vue.js
python正则表达式中的括号匹配问题
2014/12/14 Python
python安装numpy&amp;安装matplotlib&amp; scipy的教程
2017/11/02 Python
Django 路由系统URLconf的使用
2018/10/11 Python
python实现几种归一化方法(Normalization Method)
2019/07/31 Python
Pytorch 实现权重初始化
2019/12/31 Python
pytorch常见的Tensor类型详解
2020/01/15 Python
使用tensorflow根据输入更改tensor shape
2020/06/23 Python
Python logging日志库空间不足问题解决
2020/09/14 Python
10分钟理解CSS3 Grid布局
2018/12/20 HTML / CSS
css3 伪类选择器快速复习小结
2019/09/10 HTML / CSS
英国领先的在线高尔夫商店:Gamola Golf
2019/11/16 全球购物
面向对象编程是如何提高软件开发水平的
2014/05/06 面试题
《乌鸦和狐狸》教学反思
2014/02/08 职场文书
2014班子成员自我剖析材料思想汇报
2014/10/01 职场文书
学习商务礼仪心得体会
2016/01/22 职场文书
2017元旦、春节期间廉洁自律承诺书
2016/03/25 职场文书
求职自荐信该如何书写?
2019/06/24 职场文书