當下前端屆最火的技術之一莫過於React + Redux + webpack的技術結合。最近公司內部也正在轉react,這周主要作了個React的modal組件,接下來談下具體實現過程。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">×</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圖標被換成了×
。
而後寫下對應的CSS樣式。此處主要說明一下主要的樣式佈局原理,細節略過。
Modal框的背景mask樣式經過position:fixed + top/right/bottom/left:0 + height: 100%
實現。
不定寬高的主體內容水平垂直居中的實現經過position:fixed + top/left: 50% + translate(-50%, -50%)
實現。react
有了已經想好的佈局樣式,開始實現最基本的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
爲了保證咱們的組件始終處於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 } }
此時,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中。
此處代碼有點長,省略咯。正則表達式