实现弹窗的原理关键在于,如何将弹窗组件挂载到任意的dom上,参考weui.js,提供了思路,可以通过append将元素添加到指定的父节点上,来实现弹窗的显示,隐藏的时候在移除该元素即可,如下示例:

参考:https://github.com/Tencent/weui.js/blob/master/src/picker/picker.js

        在react同样可以使用该思路来实现,弹窗的显示和隐藏。但是在react中一般不这么搞,因为react已经提供了相关的API来实现,分别是unstable_renderSubtreeIntoContainer和Portal组件,其中unstable_renderSubtreeIntoContainer已经过去,被Portal替代,原因是unstable_renderSubtreeIntoContainer使用起来麻烦,而且换不稳定,主要表现在以下两点:

1、需要自己管理组件的生命周期,用React.render()渲染到某个DOM节点,如果要卸载的话需要手动执行unmountComponentAtNode()

2、接受不到Context的值。用render()渲染的组件是无法获取到上级节点的Context值的。比如多语言机制实现。

        下面主要介绍Portals的两种弹窗的用法:

一、静态弹窗

        静态弹窗是初始化渲染的时候要加载的内容已经被渲染到指定的节点里面,隐藏和显示通过变量控制。

1、dialog

import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom'

export default function Dialog(props) {
    const [node, setNode] = useState();

    useEffect(() => {
        const element = document.createElement('div');
        document.body.appendChild(element);
        setNode(element);
        return () => {
            document.body.removeChild(element);
        };
    }, []);

    return node ? ReactDOM.createPortal(props.children, node) : null;
}

2、App

import React, {useState} from 'react'
import Dialog from "./dialog";

export default function App() {
    const [show, isShow] = useState(false)
    return (
        <div>
            <button onClick={() => {
                isShow(show=> !show)
            }}>点击显示
            </button>
            {show && <Dialog>
                <div>
                    我是一个简答的弹窗
                </div>
            </Dialog>}
        </div>
    );
}

二、动态弹窗

        动态弹窗是初始化渲染的时候要加载的内容没有被渲染到指定的节点里面,需要显示的时候再加载,隐藏和显示单独控制。

1、dialog同上

2、App

import React from 'react'
import ReactDOM from 'react-dom'
import Dialog from "./dialog";

export default function App() {
    const div = document.createElement('div');
    return (
        <div>
            <button onClick={() => {
                ReactDOM.render(
                    <Dialog>
                        我是一个弹窗
                    </Dialog>,
                    div
                );
            }}>点击显示
            </button>
            <button onClick={() => {
                const unmountResult = ReactDOM.unmountComponentAtNode(div);
                if (unmountResult && div.parentNode) {
                    div.parentNode.removeChild(div);
                }
            }}>点击隐藏
            </button>
        </div>
    );
}

三、效果图

 参考文档:

https://zhuanlan.zhihu.com/p/52016989

https://react.docschina.org/docs/portals.html

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐