React對話框組件實現

當下前端屆最火的技術之一莫過於React + Redux + webpack的技術結合。最近公司內部也正在轉react,這周主要作了個React的modal組件,接下來談下具體實現過程。html

基本的HTML結構

雖然React基於虛擬DOM,但他的JSX語法仍是離不開最基本的HTML。第一步要作的就是經過HTML&&CSS實現Dialog垂直水平居中框。HTML結構以下:前端

<div className="m-mask"></div>
                <div className="m-dialog">
                    <div className="md-dialog">
                        <div className="md-dialog-title">
                            <h4>{title}</h4>
                            <span className="btn">
                                <i className="iconfont">&times;</i>
                            </span>
                        </div>
                        <div className="md-dialog-content">
                            {this.props.children}
                        </div>
                        <div className="md-dialog-foot">
                            <a href="#" className="btns">取消</a>
                            <a href="#" className="btns btns-blue">肯定</a>
                        </div>
                    </div>
                </div>

ps: JSX語法的className對應於HTML中的class,其次文中的iconfont圖標被換成了&times;
而後寫下對應的CSS樣式。此處主要說明一下主要的樣式佈局原理,細節略過。
Modal框的背景mask樣式經過position:fixed + top/right/bottom/left:0 + height: 100%實現。
不定寬高的主體內容水平垂直居中的實現經過position:fixed + top/left: 50% + translate(-50%, -50%)實現。react

React Modal Component

有了已經想好的佈局樣式,開始實現最基本的Modal組件。由於須要動態控制組件的顯隱,因此組件的顯隱在內部要經過state方便控制,而其餘屬性則經過props實現。modal.js代碼以下:webpack

import React, { Component, PropTypes } from 'react'

const defaultProps = {
    show: false,
    title: '',
    zIndex: 1000,
    onOk: () => {},
    onCancel: () => {},
}

const propTypes = {
    title: PropTypes.string,
    zIndex: PropTypes.number,
    onOk: PropTypes.func,
    onCancel: PropTypes.func,
}

export default class Modal extends Component {
    constructor(props) {
        super(props)
        this.state = {show: props.show}
    }
    render() {
        return (
                // JSX語法的HTML
                   );
    }
}

Modal.defaultProps = defaultProps
Modal.propTypes = propTypes

不過顯隱內部經過state控制,但父組件仍是須要經過props傳遞初始默認值。並且來回調用同一個modal時,父組件是經過props中的show屬性控制。內部的state仍是第一次調用時傳入的props值。這樣沒法致使及時控制顯隱。此時react的componentWillReceiveProps()出場,完美解決這個bug。
俗話說bug是解不完的,雖然上面的組件勉強能夠正常使用,可是用於樣式經過絕對定位來作的,無形中致使了另一個坑,若是Modal的父組件採用了相對或者絕對定位,即影響了Modal組件的定位,就會存在Modal出如今了某個div中,而不是理想的body中。bug復現以下:
git

unstable_renderSubtreeIntoContainer登場

爲了保證咱們的組件始終處於body中,採起了ReactDOM中的的這個不太正式的API。語法很簡單:github

ReactDOM.unstable_renderSubtreeIntoContainer(parent, component, dom)

parent通常是this,component是Modal,dom是div
代碼實現以下:web

export default class extends Component {
    appendMaskIntoDoc() {
        ReactDOM.unstable_renderSubtreeIntoContainer(
            this,
            <Modal {...this.props}>
                {this.props.children}
            </Modal>,
            this.container
        )
    }

    componentDidMount() {
        this.container = document.createElement('div')
        document.body.appendChild(this.container)
        this.appendMaskIntoDoc()
    }

    componentDidUpdate() {
        this.appendMaskIntoDoc()
    }

    componentWillUnmount() {
        document.body.removeChild(this.container)
    }

    render() {
        return null
    }
}
API形式

此時,Modal組件已經成功作出來了。父組件能夠成功調用,效果以下:

不過,偷偷see了下螞蟻金服官網的Modal組件調用,還有一種API形式的調用。因而也簡單實現了下。這裏,簡單說下實現思路吧。
Confirm function內部經過setState方法函數接受的參數傳遞給Modal的父組件dialog,onOk的promise異步回調則是在dialog內部經過處理以後再傳遞給Modal組件。
此處我是經過正則表達式檢測new Promise,若是屬於Promise,則給onOk綁定then,內部調用setState控制Modal的隱藏。不過在調用Confirm function以前,
dialog組件已經被render進ReactDOM中,render以前則須要dom節點,就須要能獲取到document節點。而後手動建立空div節點添加到body中。
此處代碼有點長,省略咯。正則表達式

完整的代碼已放到github上。https://github.com/qingguoing/react-modal
相關文章
相關標籤/搜索