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 相关文章推荐
学习YUI.Ext 第三天
Mar 10 Javascript
JavaScript 权威指南(第四版) 读书笔记
Aug 11 Javascript
Dom 结点创建 基础知识
Oct 01 Javascript
javascript自定义startWith()和endWith()的两种方法
Nov 11 Javascript
Bootstrap选项卡动态切换效果
Nov 28 Javascript
jQuery封装placeholder效果实现方法,让低版本浏览器支持该效果
Jul 08 jQuery
jQuery Position方法使用和兼容性
Aug 23 jQuery
JS与HTML结合实现流程进度展示条思路详解
Sep 03 Javascript
JS声明对象时属性名加引号与不加引号的问题及解决方法
Feb 16 Javascript
Bootstrap的aria-label和aria-labelledby属性实例详解
Nov 02 Javascript
详解vuejs2.0 select 动态绑定下拉框支持多选
Apr 25 Javascript
基于Vue实现的多条件筛选功能的详解(类似京东和淘宝功能)
May 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 获取MySQL数据库里所有表的实现代码
2011/07/13 PHP
PHP用星号隐藏部份用户名、身份证、IP、手机号等实例
2014/04/08 PHP
PHP小教程之实现链表
2014/06/09 PHP
php+mysql实现用户注册登陆的方法
2015/01/03 PHP
PHP 中 DOMDocument保存xml时中文出现乱码问题的解决方案
2016/09/19 PHP
php正则去除网页中所有的html,js,css,注释的实现方法
2016/11/03 PHP
PHP使用redis消息队列发布微博的方法示例
2017/06/22 PHP
Javascript下IE与Firefox下的差异兼容写法总结
2010/06/18 Javascript
jQuery find和children方法使用
2011/01/31 Javascript
JQuery中$之选择器用法介绍
2011/04/05 Javascript
JS实现简易刻度时钟示例代码
2017/03/11 Javascript
Angular17之Angular自定义指令详解
2018/01/21 Javascript
vue 标签属性数据绑定和拼接的实现方法
2018/05/17 Javascript
React+Antd+Redux实现待办事件的方法
2019/03/14 Javascript
Vue多环境代理配置方法思路详解
2019/06/21 Javascript
koa2+vue实现登陆及登录状态判断
2019/08/15 Javascript
node.js开发辅助工具nodemon安装与配置详解
2020/02/06 Javascript
JS+canvas五子棋人机对战实现步骤详解
2020/06/04 Javascript
简单了解Vue computed属性及watch区别
2020/07/10 Javascript
[02:42]DOTA2英雄基础教程 杰奇洛
2013/12/23 DOTA
[01:20:47]DOTA2-DPC中国联赛 正赛 Ehome vs Magma BO3 第一场 1月19日
2021/03/11 DOTA
深入理解Python对Json的解析
2017/02/14 Python
python 与GO中操作slice,list的方式实例代码
2017/03/20 Python
python将txt文档每行内容循环插入数据库的方法
2018/12/28 Python
python和js交互调用的方法
2020/06/23 Python
HTML5本地存储之IndexedDB
2017/06/16 HTML / CSS
J2ee常用的设计模式?说明工厂模式
2015/05/21 面试题
护理学专业推荐信
2013/12/03 职场文书
兼职业务员岗位职责
2014/01/01 职场文书
义和团口号
2014/06/17 职场文书
安全演讲稿开场白
2014/08/25 职场文书
2014乡镇班子个人对照检查材料思想汇报
2014/09/26 职场文书
2015年助理政工师工作总结
2015/05/26 职场文书
Python函数中的不定长参数相关知识总结
2021/06/24 Python
uni-app 微信小程序授权登录的实现步骤
2022/02/18 Javascript
win11电脑关机鼠标灯还亮怎么解决? win11关机后鼠标灯还亮解决方法
2023/01/09 数码科技