react modal 的 简单实现 与 原理分析

作者: JasonFF | 来源:发表于2016-06-29 16:31 被阅读4550次

    在React项目中,由于所有的Component将会被render在body的一个div之中,并且往往是Component包Component,就像一个洋葱一样,一层包着一层,里层的很难触及比较外面的一层。

    可是,在css中,position属性往往被外层的position所左右,height: 100% 往往被外层的height所左右。如何才能做出一个拥有半透明的黑色遮罩,罩住整个页面,从而实现modal的效果呢?

    在react 中,modal 的思路就是制作一个<Modal></Modal> Component,但是把它render 到body 的下一层去,而不是跟其他Component 一样render 到Component 的最里层。

    只有render在body的下一层,与现有的Component 组平起平坐,这样才完全脱离的样式局限,当我在<Modal></Modal> 设置样式的时候可以为所欲为。

    在这里就要借助 react-dom 了。因为render方法是 react-dom 提供的;
    下面将是我测试的代码。

    import React, {Component, PropTypes} from 'react';
    import ReactDOM from 'react-dom';
    
    export default class Modal extends Component {
        static defaultProps = {
            open: false
        };
        componentWillReceiveProps(nextProps) {
            if (nextProps.open && !this.props.open) { // 从无到有
                this.node = document.createElement('div'); // 创建 DOM
                this.node.className = 'ReactModal'; // 给上 ClassName
                document.getElementsByTagName('body')[0].appendChild(this.node) // 给 body 加上刚才的 带有 className 的 div
                // 这个时候创建了 render的目的地。
                const style = require('./style.scss'); // css 样式
                const {children, ...rest} = nextProps;
                let modal = (
                    <div className={style.container}>
                        <div className={style.mask} {...rest}></div>
                        {nextProps.children}
                    </div>
                );
                // 这个时候创建了 Modal 的虚拟 Dom
                let allClass = document.getElementsByClassName('ReactModal');
                ReactDOM.render(modal, allClass[allClass.length - 1]) // 之所以这么写,是因为能重复打开Modal,因为每一次打开Modal,都会建立一个div
                // 将 Modal 成功 render 到目的地
            }
            if (this.props.open && !nextProps.open) { // 从有到无
                ReactDOM.unmountComponentAtNode(this.node) // 调用 react-dom unmountComponentAtNode方法,将Modal解除。
                // 或者可以写下面的方法,将整个创建的div删除,这样多次打开就不会有很多个div残留在body中,但是并不是很正规的做法。
                // document.getElementsByTagName('body')[0].removeChild(document.getElementsByClassName('ReactModal')[0])
            }
        }
        render() {
            return null // 只要这个Component的方法,不要它的render,它的render将会render到内层。
        }
    }
    
    
    
    Paste_Image.png

    选中处为刚添加的dom,它被正确的render到body下一层,与** #content **平起平坐,里面有内容,上面的div为多次打开关闭Modal之后残留的div。

    相关文章

      网友评论

      • threeSmile:请问如何更新组件内部的state呢?
      • Yi罐可乐:三个月后再来评论下: 新项目要用到 modal 组件,考虑再三,把博主的代码搬过来直接用了,哈哈
        JasonFF:@yezhiqiusev 其他还没有去研究过。。
        叶_知秋:这个在react路由的嵌套比较深的子页面里面添加全局遮罩,除了这个方法,不知道还有没有其他的方法。
        JasonFF:@Yi罐可乐 嘻嘻,你可以用很多react库,现在都很全的。建议知乎搜索react组件库,方便快速开发
      • Yi罐可乐:有用!已赞!
        不过实际项目里想用「半透明的黑色遮罩」还有别的思路,
        不必非要插入到 body 的最外层,在深层里面随便定义个 黑色遮罩 div 都可以的。

        但是楼主的这个方法挺好,用 react 那么久了还不知道有这个方法,还有我觉得它不仅仅能加遮罩。
        Yi罐可乐:@JasonFF 好的!:smile:
        JasonFF:@Yi罐可乐 写到里面会有一些限制。当时也研究了react bootstrap 的一些组件,推荐你也可以研究学习它。:smile:

      本文标题:react modal 的 简单实现 与 原理分析

      本文链接:https://www.haomeiwen.com/subject/anlxjttx.html