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

4 篇文章 0 订阅
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 了。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值