react學習之彈出層


react的彈出層不同於以往的DOM編程,我們知道,在DOM中,彈出層事件綁定在對應的節點上即可,但是在react中,往往只能實現父子之間的傳遞控制,顯然,彈出層的層級不符合此關系。
在這里我們需要使用React官方的portals

portals可以幫助我們將子節點插入到父節點層級之外的地方
注:官方文檔使用的是class,我在這里使用的是react hook
在react

前置知識

react hook
useEffect是了react生命周期中的componentDidMountcomponentDidUpdate以及componentWillUnMount三個鈎子函數的組合。

  • useEffect有兩個參數
  • useEffect第二個參數為空數組相當於在componentDidMount周期執行一次
  • useEffect第二個參數為含有某種state的數組相當於只有在這個state發生改變的時候才執行
  • useEffect返回一個函數相當於在componentWillUnMount周期執行一次

實現步驟

1.首先,選擇要插入彈出層的DOM節點,在這里我參照官方文檔將整個項目分成了app-rootmodel-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插入DOM

(1)首先獲取我們要插入的DOM節點id=model-root

 const modelRoot = document.getElementById('model-root');

(2)創建一個存放子節點的元素el

const [el,changEl] = useState(document.createElement('div'));

(3)在componentDidMount階段將el節點插入model-root

    //初始化工作
    useEffect(()=>{

        modelRoot.appendChild(el);

    },[])

(4)渲染組件,執行createPortal方法

    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;

最終的丑陋效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM