React如何將組件渲染到指定DOM節(jié)點詳解
前言
眾所周知React優(yōu)點之一就是他的API特別簡單。通過render 方法返回一個組件的基本結(jié)構(gòu),如同一個簡單的函數(shù),就可以得到一個可以復(fù)用的react組件。但是有時候還是會有些限制的,尤其是他的API中,不能控制組件所應(yīng)該渲染到的DOM節(jié)點,這就讓一些彈層組件很難控制。當(dāng)父元素設(shè)置為overflow:hidden 的時候,問題就會出現(xiàn)了。
例如就像下面的這樣:

我們實際期待的效果是這樣的:

幸運的是,雖然不是很明顯,但有一個相當(dāng)優(yōu)雅的方式來繞過這個問題。我們學(xué)到的第一個react函數(shù)是render 方法,他的函數(shù)簽名是這樣的:
ReactComponent render( ReactElement element, DOMElement container, [function callback] )
通常情況下我們使用該方法將整個應(yīng)用渲染到一個DOM節(jié)點中。好消息是該方法并不僅僅局限于此。我們可以在一個組件中,使用ReactDom.render 方法將另一個組件渲染到一個指定的DOM 元素中。作為一個組件的render 方法,其必須是純凈的(例如:不能改變state或者與DOM交互).所以我們需要在componentDidUpdate 或者 componentDidMount 中調(diào)用ReactDom.render 方法。
另外我們需要確保在父元素被卸載的時候,改組件也要被卸載掉.
整理下,我們得到下面的一個組件:
import React,{Component} from 'react';
import ReactDom from 'react-dom';
export default class RenderInBody extends Component{
constructor(p){
super();
}
componentDidMount(){//新建一個div標(biāo)簽并塞進(jìn)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標(biāo)簽
ReactDom.render(this.props.children, this.popup);
}
render(){
return null;
}
}
總結(jié)下就是:
在componentDidMount的時候手動向body內(nèi)塞一個div標(biāo)簽,然后使用ReactDom.render 將組件渲染到這個div標(biāo)簽
當(dāng)我們想把組件直接渲染到body上的時候,只需要在該組件的外面包一層RenderInBody 就可以了.
export default class Dialog extends Component{
render(){
return {
<RenderInBody>i am a dialog render to body</RenderInBody>
}
}
}
譯者增加:
將以上組件改造一下,我們就可以向指定的dom節(jié)點中渲染和卸載組件,并加上位置控制,如下:
//此組件用于在body內(nèi)渲染彈層
import React,{Component} from 'react'
import ReactDom from 'react-dom';
export default class RenderInBody extends Component{
constructor(p){
super(p);
}
componentDidMount(){
/**
popupInfo={
rootDom:***,//接收彈層組件的DOM節(jié)點,如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;
}
}
注:位置獲取和根結(jié)點判斷函數(shù)
export default (dom,classFilters)=> {
let left = dom.offsetLeft,
top = dom.offsetTop + dom.scrollTop,
current = dom.offsetParent,
rootDom = accessBodyElement(dom);//默認(rèn)是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:為響應(yīng)彈層的dom節(jié)點,或者到該dom的位置后,可以做位置的微調(diào),讓彈層位置更佳合適
*
2. classFilters:需要接收彈層組件的DOM節(jié)點的篩選類名
/
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
React報錯map()?is?not?a?function詳析
這篇文章主要介紹了React報錯map()?is?not?a?function詳析,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08
React實現(xiàn)一個高度自適應(yīng)的虛擬列表
這篇文章主要介紹了React如何實現(xiàn)一個高度自適應(yīng)的虛擬列表,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下2021-04-04
react+antd4實現(xiàn)優(yōu)化大批量接口請求
這篇文章主要為大家詳細(xì)介紹了如何使用react hooks + antd4實現(xiàn)大批量接口請求的前端優(yōu)化,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-02-02
解析TypeError:import_react_native.AppState.removeEventListener
這篇文章主要為大家介紹了TypeError:import_react_native.AppState.removeEventListener?is?not?a?function問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09

