天堂旅行者 發表於 2019-6-5 17:26:00

react学习之弹出层

<p>react的弹出层不同于以往的DOM编程,我们知道,在DOM中,弹出层事件绑定在对应的节点上即可,但是在react中,往往只能实现父子之间的传递控制,显然,弹出层的层级不符合此关系。<br>
在这里我们需要使用React官方的portals</p>
<p>portals可以帮助我们将子节点插入到父节点层级之外的地方<br>
注:官方文档使用的是class,我在这里使用的是react hook<br>
在react</p>
<h2 id="前置知识">前置知识</h2>
<p>react hook<br>
<code>useEffect</code>是了react生命周期中的<code>componentDidMount</code>、<code>componentDidUpdate</code>以及<code>componentWillUnMount</code>三个钩子函数的组合。</p>
<ul>
<li><code>useEffect</code>有两个参数</li>
<li><code>useEffect</code>第二个参数为空数组相当于在<code>componentDidMount</code>周期执行一次</li>
<li><code>useEffect</code>第二个参数为含有某种state的数组相当于只有在这个state发生改变的时候才执行</li>
<li><code>useEffect</code>返回一个函数相当于在<code>componentWillUnMount</code>周期执行一次</li>
</ul>
<h2 id="实现步骤">实现步骤</h2>
<p>1.首先,选择要插入弹出层的DOM节点,在这里我参照官方文档将整个项目分成了<code>app-root</code>和<code>model-root</code>两层,我将把弹出层插入到<code>model-root</code>节点中</p>
<pre><code>function App(){
    return(
      &lt;React.Fragment&gt;
            &lt;div id={"app-root"}&gt;
                &lt;Router/&gt;

            &lt;/div&gt;
            
            &lt;div id={"model-root"}&gt;&lt;/div&gt;
      &lt;/React.Fragment&gt;
    )
}
export default App;
</code></pre>
<p>2.实现弹出层<br>
我们按照官方文档,先生成一个节点el作为存放我们子节点的容器,并执行<code>ReactDOM.createPortal</code></p>
<pre><code>ReactDOM.createPortal(child, container)
</code></pre>
<p>我们需要先将我们的el节点插入选定的DOM节点,然后再将portal元素插入DOM树中,故我们先用hook在<code>componentDidMount</code>阶段将el插入DOM</p>
<p>(1)首先获取我们要插入的DOM节点id=model-root</p>
<pre><code> const modelRoot = document.getElementById('model-root');
</code></pre>
<p>(2)创建一个存放子节点的元素el</p>
<pre><code>const = useState(document.createElement('div'));
</code></pre>
<p>(3)在<code>componentDidMount</code>阶段将el节点插入model-root</p>
<pre><code>    //初始化工作
    useEffect(()=&gt;{

      modelRoot.appendChild(el);

    },[])
</code></pre>
<p>(4)渲染组件,执行createPortal方法</p>
<pre><code>    return ReactDOM.createPortal((
      &lt;Content closeModel={props.closeModel}/&gt;
    ), el);
</code></pre>
<p>(5)在<code>componentWillUnMount</code>阶段移除我们的el节点</p>
<pre><code>    //清理工作
    useEffect(()=&gt;{
      return ()=&gt;{
            modelRoot.innerHTML="";

      }
    })
</code></pre>
<p>完整代码如下:</p>
<pre><code>import React,{useState,useEffect} from 'react';
import './Model.css';
import ReactDOM from "react-dom";
import ExcelUtil from '../../utils/excelUtil';


function Content(props) {
    return(
      &lt;div className={'cover'}&gt;
            &lt;button onClick={props.closeModel}&gt;关闭&lt;/button&gt;
            &lt;input type='file' accept='.xlsx, .xls' onChange={(e)=&gt;{ExcelUtil.importExcel(e)} }/&gt;

      &lt;/div&gt;
    )
}

function Model(props){
    const appRoot = document.getElementById('app-root');
    const modelRoot = document.getElementById('model-root');
    const = useState(document.createElement('div'));

    //初始化工作
    useEffect(()=&gt;{

      modelRoot.appendChild(el);

    },[])
    //清理工作
    useEffect(()=&gt;{
      return ()=&gt;{
            modelRoot.innerHTML="";

      }
    })
    return ReactDOM.createPortal((
      &lt;Content closeModel={props.closeModel}/&gt;
    ), el);
}

export default Model;
</code></pre>
<p>这样子子元素就出现在了我们想要的DOM层级中</p>
<p>3.在调用页中引入我们的Model并定义相关触发事件,这些与子节点向父节点的方式传值无异</p>
<pre><code>{(isShowPop == true)?&lt;Model isShow={isShowPop} closeModel={handleInClick}/&gt;:null}
</code></pre>
<pre><code>
function RegisterInUser() {
    const = useState(false);
    function handleInClick(){
      changeShowPop(!isShowPop);
    }
    return(
      &lt;React.Fragment&gt;
//这里是使用的地方
            {(isShowPop == true)?&lt;Model isShow={isShowPop} closeModel={handleInClick}/&gt;:null}


            &lt;button className="ui-button ui-button-primary"onClick={handleInClick}&gt;导入人员&lt;/button&gt;
            &lt;button
                className="ui-button ui-button-primary outExcelBtn"
                type="primary"
                onClick={() =&gt; {ExcelUtil.exportExcel(initColumn, attendanceInfoList,"人员名单.xlsx")}}&gt;
                导出表格
            &lt;/button&gt;


      &lt;/React.Fragment&gt;
    )
}

export default RegisterInUser;

</code></pre>
<h2 id="最终的丑陋效果">最终的丑陋效果</h2>
<p><img src="https://img2018.cnblogs.com/blog/1394463/201906/1394463-20190605172503737-1873170032.png" alt="" loading="lazy"></p>
<p><img src="https://img2018.cnblogs.com/blog/1394463/201906/1394463-20190605172532782-1383307045.png" alt="" loading="lazy"></p><br><br>
来源:https://www.cnblogs.com/yuyuan-bb/p/10980834.html
頁: [1]
查看完整版本: react学习之弹出层