欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

React如何将组件渲染到指定DOM节点详解

程序员文章站 2022-05-14 19:03:08
前言 众所周知react优点之一就是他的api特别简单。通过render 方法返回一个组件的基本结构,如同一个简单的函数,就可以得到一个可以复用的react组件。但是有时...

前言

众所周知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节点的筛选类名
/

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。