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 相关文章推荐
javascript 获取页面的高度及滚动条的位置的代码
May 06 Javascript
使用jquery mobile做幻灯播放效果实现步骤
Jan 04 Javascript
JS获取select的value和text值的简单实例
Feb 26 Javascript
JavaScript中的console.assert()函数介绍
Dec 29 Javascript
简介JavaScript中setUTCSeconds()方法的使用
Jun 12 Javascript
js实现浏览本地文件并显示扩展名的方法
Aug 17 Javascript
easyUI实现类似搜索框关键词自动提示功能示例代码
Dec 27 Javascript
JavaScript实现水平进度条拖拽效果
Jan 18 Javascript
Angular2入门--架构总览
Mar 29 Javascript
一百行JS代码实现一个校验工具
Apr 30 Javascript
JS一次前端面试经历记录
Mar 19 Javascript
如何利用JS将手机号中间四位变成*号
Sep 29 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
利用curl抓取远程页面内容的示例代码
2013/07/23 PHP
在openSUSE42.1下编译安装PHP7 的方法
2015/12/24 PHP
浅谈PHP封装CURL
2019/03/06 PHP
JavaScript 学习笔记(十一)
2010/01/19 Javascript
ExtJS 设置级联菜单的默认值
2010/06/13 Javascript
innerText和textContent对比及使用介绍
2013/02/27 Javascript
js实现在同一窗口浏览图片
2014/09/17 Javascript
jQuery实现隔行背景色变色
2014/11/24 Javascript
原生javaScript实现图片延时加载的方法
2014/12/22 Javascript
js判断某个方法是否存在实例代码
2015/01/10 Javascript
JavaScript使用encodeURI()和decodeURI()获取字符串值的方法
2015/08/04 Javascript
js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解
2016/04/01 Javascript
详解Javascript中prototype属性(推荐)
2016/09/03 Javascript
微信小程序 在Chrome浏览器上运行以及WebStorm的使用
2016/09/27 Javascript
解决vue keep-alive 数据更新的问题
2018/09/21 Javascript
详解JavaScript的内存空间、赋值和深浅拷贝
2019/04/17 Javascript
vue实现自定义H5视频播放器的方法步骤
2019/07/01 Javascript
解决layui数据表格排序图标被超出的表头挤出去的问题
2019/09/19 Javascript
vue自定义组件(通过Vue.use()来使用)即install的用法说明
2020/08/11 Javascript
微信小程序入门之指南针
2020/10/22 Javascript
Django框架的使用教程路由请求响应的方法
2018/07/03 Python
Python使用gRPC传输协议教程
2018/10/16 Python
python matplotlib包图像配色方案分享
2020/03/14 Python
Pycharm创建python文件自动添加日期作者等信息(步骤详解)
2021/02/03 Python
10 套华丽的CSS3 按钮小结
2012/10/03 HTML / CSS
JACK & JONES英国官方网站:欧洲领先的男装生产商
2017/09/27 全球购物
Bibloo奥地利:购买女装、男装、童装、鞋和配件
2018/10/18 全球购物
英国排名第一的停车场运营商:NCP
2019/08/26 全球购物
网上常见的一份Linux面试题(多项选择部分)
2015/02/07 面试题
会计实习生自我鉴定
2013/12/12 职场文书
文科教师毕业的自我评价
2014/01/16 职场文书
内蒙古鄂尔多斯市市长寄语
2014/04/10 职场文书
2014校长四风问题对照检查材料思想汇报
2014/09/16 职场文书
大学生青年志愿者活动总结
2015/05/06 职场文书
暗恋桃花源观后感
2015/06/12 职场文书
基于PyQT5制作一个桌面摸鱼工具
2022/02/15 Python