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实现搜索框提示功能示例代码
Aug 13 Javascript
JavaScript实现列出数组中最长的连续数
Dec 29 Javascript
JavaScript使用Replace进行字符串替换的方法
Apr 14 Javascript
jQuery插件WebUploader实现文件上传
Nov 07 Javascript
5种JavaScript脚本加载的方式
Jan 16 Javascript
canvas绘图不清晰的解决方案
Feb 28 Javascript
JS中利用localStorage防止页面动态添加数据刷新后数据丢失
Mar 10 Javascript
JavaScript方法_动力节点Java学院整理
Jun 28 Javascript
JS获取url参数,JS发送json格式的POST请求方法
Mar 29 Javascript
js事件触发操作实例分析
Jun 21 Javascript
JS document form表单元素操作完整示例
Jan 13 Javascript
手把手教你实现 Promise的使用方法
Sep 02 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
快速配置PHPMyAdmin方法
2008/06/05 PHP
网页上facebook分享功能具体实现
2014/01/26 PHP
PHP常用数组函数介绍
2014/07/28 PHP
ThinkPHP中ajax使用实例教程
2014/08/22 PHP
使用 stylelint检查CSS_StyleLint
2016/04/28 Javascript
整理JavaScript对DOM中各种类型的元素的常用操作
2016/05/05 Javascript
静态页面html中跳转传值的JS处理技巧
2016/06/22 Javascript
jQuery 3.0 的 setter和getter 模式详解
2016/07/11 Javascript
老生常谈js动态添加事件--- 事件委托
2016/07/19 Javascript
WebSocket+node.js创建即时通信的Web聊天服务器
2016/08/08 Javascript
浅谈Express异步进化史
2017/09/09 Javascript
利用vue组件自定义v-model实现一个Tab组件方法示例
2017/12/06 Javascript
详解Vue组件之作用域插槽
2018/11/22 Javascript
js计时事件实现圆形时钟
2020/03/25 Javascript
原生js+canvas实现下雪效果
2020/08/02 Javascript
vue实现在进行增删改操作后刷新页面
2020/08/05 Javascript
详解Tensorflow数据读取有三种方式(next_batch)
2018/02/01 Python
Python给定一个句子倒序输出单词以及字母的方法
2018/12/20 Python
python3 自动识别usb连接状态,即对usb重连的判断方法
2019/07/03 Python
Python魔法方法 容器部方法详解
2020/01/02 Python
Python Django2 model 查询介绍(条件、范围、模糊查询)
2020/03/16 Python
css3选择器基本介绍
2014/12/15 HTML / CSS
Avène雅漾美国官方网站:敏感肌肤护理专家
2016/10/24 全球购物
罗技英国官方网站:Logitech UK
2020/11/03 全球购物
外企财务年会演讲稿
2014/01/03 职场文书
新护士岗前培训制度
2014/02/02 职场文书
物流业务员岗位职责
2014/02/08 职场文书
节约能源标语
2014/06/17 职场文书
入党积极分子学习党的纲领思想汇报
2014/09/13 职场文书
不服从公司安排检讨书
2014/09/24 职场文书
2015年师德表现自我评价
2015/03/05 职场文书
CSS3实现的侧滑菜单
2021/04/27 HTML / CSS
vue如何批量引入组件、注册和使用详解
2021/05/12 Vue.js
JS + HTML 罗盘式时钟的实现
2021/05/21 Javascript
JavaScript最完整的深浅拷贝实现方式详解
2022/02/28 Javascript
css3新特性的应用示例分析
2022/03/16 HTML / CSS