react的彈出層不一樣於以往的DOM編程,咱們知道,在DOM中,彈出層事件綁定在對應的節點上便可,可是在react中,每每只能實現父子之間的傳遞控制,顯然,彈出層的層級不符合此關係。
在這裏咱們須要使用React官方的portalscss
portals能夠幫助咱們將子節點插入到父節點層級以外的地方
注:官方文檔使用的是class,我在這裏使用的是react hook
在reacthtml
react hook
useEffect
是了react生命週期中的componentDidMount
、componentDidUpdate
以及componentWillUnMount
三個鉤子函數的組合。react
useEffect
有兩個參數useEffect
第二個參數爲空數組至關於在componentDidMount
週期執行一次useEffect
第二個參數爲含有某種state的數組至關於只有在這個state發生改變的時候才執行useEffect
返回一個函數至關於在componentWillUnMount
週期執行一次1.首先,選擇要插入彈出層的DOM節點,在這裏我參照官方文檔將整個項目分紅了app-root
和model-root
兩層,我將把彈出層插入到model-root
節點中編程
function App(){ return( <React.Fragment> <div id={"app-root"}> <Router/> </div> <div id={"model-root"}></div> </React.Fragment> ) } export default App;
2.實現彈出層
咱們按照官方文檔,先生成一個節點el做爲存放咱們子節點的容器,並執行ReactDOM.createPortal
數組
ReactDOM.createPortal(child, container)
咱們須要先將咱們的el節點插入選定的DOM節點,而後再將portal元素插入DOM樹中,故咱們先用hook在componentDidMount
階段將el插入DOMapp
(1)首先獲取咱們要插入的DOM節點id=model-rootdom
const modelRoot = document.getElementById('model-root');
(2)建立一個存放子節點的元素el函數
const [el,changEl] = useState(document.createElement('div'));
(3)在componentDidMount
階段將el節點插入model-rootui
//初始化工做 useEffect(()=>{ modelRoot.appendChild(el); },[])
(4)渲染組件,執行createPortal方法excel
return ReactDOM.createPortal(( <Content closeModel={props.closeModel}/> ), el);
(5)在componentWillUnMount
階段移除咱們的el節點
//清理工做 useEffect(()=>{ return ()=>{ modelRoot.innerHTML=""; } })
完整代碼以下:
import React,{useState,useEffect} from 'react'; import './Model.css'; import ReactDOM from "react-dom"; import ExcelUtil from '../../utils/excelUtil'; function Content(props) { return( <div className={'cover'}> <button onClick={props.closeModel}>關閉</button> <input type='file' accept='.xlsx, .xls' onChange={(e)=>{ExcelUtil.importExcel(e)} }/> </div> ) } function Model(props){ const appRoot = document.getElementById('app-root'); const modelRoot = document.getElementById('model-root'); const [el,changEl] = useState(document.createElement('div')); //初始化工做 useEffect(()=>{ modelRoot.appendChild(el); },[]) //清理工做 useEffect(()=>{ return ()=>{ modelRoot.innerHTML=""; } }) return ReactDOM.createPortal(( <Content closeModel={props.closeModel}/> ), el); } export default Model;
這樣子子元素就出如今了咱們想要的DOM層級中
3.在調用頁中引入咱們的Model並定義相關觸發事件,這些與子節點向父節點的方式傳值無異
{(isShowPop == true)?<Model isShow={isShowPop} closeModel={handleInClick}/>:null}
function RegisterInUser() { const [isShowPop,changeShowPop] = useState(false); function handleInClick(){ changeShowPop(!isShowPop); } return( <React.Fragment> //這裏是使用的地方 {(isShowPop == true)?<Model isShow={isShowPop} closeModel={handleInClick}/>:null} <button className="ui-button ui-button-primary" onClick={handleInClick}>導入人員</button> <button className="ui-button ui-button-primary outExcelBtn" type="primary" onClick={() => {ExcelUtil.exportExcel(initColumn, attendanceInfoList,"人員名單.xlsx")}}> 導出表格 </button> </React.Fragment> ) } export default RegisterInUser;