React 的弹框实现(类 Antd 的 append 到 body)

版权声明: https://blog.csdn.net/huangpb123/article/details/82765635

Modal, PopUP, Toast, ToolTip 等这些都属于弹框。平时我们使用弹框一般有两种方式:一种是通过函数形式弹出,另一种是组件形式弹框。

下面我分别对两种弹出方式写了2个 Demo,如果有可以优化的地方,请多多指点。。。

函数形式弹出

// mask.js
import React from 'react';
import {Button} from 'antd';
import ReactDOM from 'react-dom';

const styles = {
    mask: {
        position: 'fixed',
        top: 0,
        right: 0,
        left: 0,
        bottom: 0,
        backgroundColor: 'rgba(0, 0, 0, 0.65)',
        height: '100%',
        zIndex: 1000,
    },
    modalWrap: {
        position: 'fixed',
        top: 0,
        right: 0,
        left: 0,
        bottom: 0,
        zIndex: 1000,
    },
    modal: {
        fontSize: 14,
        padding: 20,
        width: 520,
        height: 200,
        margin: '100px auto 0',
        backgroundColor: '#fff',
        borderRadius: 4,
        overflow: 'hidden',
        textAlign: 'center',
    },
    btnGroup: {
        padding: 10,
        textAlign: 'right'
    }
};

export default {
    dom: null, //被append的元素

    success ({title, content, onOk, onCancel}) {
        this.close();

        this.dom = document.createElement('div');

        // JSX代码
        const JSXdom = (
            <div>
                <div style={styles.mask} />
                <div style={styles.modalWrap}>
                    <div style={styles.modal}>
                        <h2>{title}</h2>
                        <p>{content}</p>
                        <div style={styles.btnGroup}>
                            <Button onClick={() => this.onCancel(onCancel)}>取消</Button>
                            <Button type="primary" onClick={() => this.onOk(onOk)}>确定</Button>
                        </div>
                    </div>
                </div>
            </div>
        );

        ReactDOM.render(JSXdom, this.dom);
        document.body.appendChild(this.dom);
    },

    onCancel (onCancel) {
        (onCancel instanceof Function) && onCancel();
        this.close();
    },

    onOk (onOk) {
        (onOk instanceof Function) && onOk();
        this.close();
    },

    close () {
        this.dom && this.dom.remove();
    }
}

怎么使用?调用 mask.js 里的 success 方法。

import Mask from './mask';

export default class Home extends React.Component {
   showModal () {
        Mask.success({
            title: 'Modal',
            content: 'Hello World !',
            onCancel: () => {
                console.log('Cancel');
            },
            onOk: () => {
                console.log('Ok');
            }
        })
    }

    render () {
        return (
            <button onClick={this.showModal}>JS显示弹框</button>
        )
    }
}

组件形式弹框

import React, {Component} from 'react';
import {Button} from 'antd';
import ReactDOM from 'react-dom';


const styles = {
    mask: {
        position: 'fixed',
        top: 0,
        right: 0,
        left: 0,
        bottom: 0,
        backgroundColor: 'rgba(0, 0, 0, 0.65)',
        height: '100%',
        zIndex: 1000,
    },
    modalWrap: {
        position: 'fixed',
        top: 0,
        right: 0,
        left: 0,
        bottom: 0,
        zIndex: 1000,
    },
    modal: {
        fontSize: 14,
        padding: 20,
        width: 520,
        height: 200,
        margin: '100px auto 0',
        backgroundColor: '#fff',
        borderRadius: 4,
        overflow: 'hidden',
        textAlign: 'center',
    },
    btnGroup: {
        padding: 10,
        textAlign: 'right'
    }
};

export default class MaskEle extends Component {
    constructor (props) {
        super(props);

        this.modal = null;
    }

    componentDidMount () {
        this.modal = document.createElement('div');
        this.props.visible && document.body.appendChild(this.modal);

        this._renderLayer();
    }

    componentDidUpdate () {
        if (this.props.visible) {
            document.body.appendChild(this.modal);
            this._renderLayer();
        } else {
            this.modal.parentNode.removeChild(this.modal);
        }
    }

    onCancel = () => {
        const { onCancel } = this.props;
        (onCancel instanceof Function) && onCancel();
    }

    onOk = () => {
        const { onOk } = this.props;
        (onOk instanceof Function) && onOk();
    }

    // 渲染模态框内容
    _renderLayer () {
        const {title, content} = this.props;

        let JSXdom = (
            <div>
                <div style={styles.mask} />
                <div style={styles.modalWrap}>
                    <div style={styles.modal}>
                        <h2>{title}</h2>
                        <p>{content}</p>
                        <div style={styles.btnGroup}>
                            <Button onClick={this.onCancel}>取消</Button>
                            <Button type="primary" onClick={this.onOk}>确定</Button>
                        </div>
                    </div>
                </div>
            </div>
        );

        ReactDOM.render(JSXdom, this.modal);
    }

    render () {
        return null;
    }
}

使用方法:通过控制 visible 属性来控制弹框的显示和隐藏。

import {Button} from 'antd';
import ModalEle from './modalEle';


export default class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            visible: false
        }
    }

    showModal = () => {
        this.setState({
            visible: true
        })
    }

    onCancel = () => {
        this.setState({
            visible: false
        })
    }

    onOk = () => {
        this.setState({
            visible: false
        })
    }

    render() {
        return (
          <div>
            <Button onClick={this.showModal}>Ele显示弹框</Button>

            <ModalEle visible={visible} 
                      title="Title" 
                      content="test" 
                      onOk={this.onOk} 
                      onCancel={this.cancel}
            />
          </div>
        )
    }
}

通用的弹窗是直接挂载到 document.body 上,比如 Antd 的弹框默认都是挂载到 document.body 上的。但有些时候你也可以自定义挂载的父元素,可以对上面代码稍加改进,把要挂载的父元素, left, top 封装成一个对象传入,然后内部稍微改一下就 OK 了。

猜你喜欢

转载自blog.csdn.net/huangpb123/article/details/82765635