React實現(xiàn)動態(tài)調(diào)用的彈框組件
最近在用react開發(fā)項目,遇到一個需求——開發(fā)一個彈框組件。在react中創(chuàng)建一個組件是很簡單的,只需要使用class創(chuàng)建并引入就可以了,但是要做到可以用js調(diào)用這個組件而不是寫在jsx結(jié)構(gòu)里,那就需要用到ReactDOM.render這個方法了。
首先先來屢一下需求:
1、彈框里的可配置字段:標(biāo)題文字,提示文字,確認(rèn)和取消按鈕的顯示隱藏以及文字。
2、點擊確認(rèn)和取消按鈕后,可以觸發(fā)相應(yīng)的事件。
3、是否為短提示,短提示的時候,確認(rèn)和取消按鈕隱藏,并且2s后消失。
接下來用兩種方法創(chuàng)建一個彈框組件,并比較一下這兩種的差異。
下面先來實現(xiàn)一個普通的寫在jsx結(jié)構(gòu)里的組件:
彈框組件:DialogAlert.js
import React, { Component } from 'react'; import './index.scss'; ? class DialogAlert extends Component { ? ? constructor(props){ ? ? ? ? super(props); ? ? ? ? this.state = { ? ? ? ? ? ? alertStatus:false, ? ? ? ? ? ? alertTitle:'提示', //標(biāo)題 ? ? ? ? ? ? alertTip:'網(wǎng)絡(luò)錯誤', //提示 ? ? ? ? ? ? cancelText:'取消', ? ? ? ? ? ? confirmText:'確認(rèn)', ? ? ? ? ? ? ? isShortTip:false, //是否為短提示,短提示的情況下不顯示'取消''確認(rèn)'(且2s后消失),且優(yōu)先級最高,其他配置無效 ? ? ? ? ? ? ? isShowCancel:true, //是否顯示確認(rèn)按鈕 ? ? ? ? ? ? isShowConfirm:true, //是否顯示確認(rèn)按鈕 ? ? ? ? ? ? ? cancelCallbackFn:function(){}, //取消 回調(diào)函數(shù) ? ? ? ? ? ? confirmCallbackFn:function (){}//確認(rèn) 回調(diào)函數(shù) ? ? ? ? } ? ? } ? ? ? componentWillReceiveProps(nextProps) { ? ? ? ? let options = nextProps.dialogOpt || {}; ? ? ? ? ? //如果是短提示 ? ? ? ? if(options.isShortTip){ ? ? ? ? ? ? options.isShowCancel = false; ? ? ? ? ? ? options.isShowConfirm = false; ? ? ? ? ? ? setTimeout(()=>{ ? ? ? ? ? ? ? ? this.close() ? ? ? ? ? ? },2000) ? ? ? ? } ? ? ? ? ? this.setState({ ? ? ? ? ? ? ...options ? ? ? ? }) ? ? } ? ? ? //取消 ? ? cancel = () => { ? ? ? ? this.state.cancelCallbackFn(); ? ? ? ? this.close() ? ? } ? ? //確認(rèn) ? ? confirm = () => { ? ? ? ? this.state.confirmCallbackFn(); ? ? ? ? this.close() ? ? } ? ? close = () => { ? ? ? ? this.setState({ ? ? ? ? ? ? alertStatus:false ? ? ? ? }) ? ? } ? ? ? render(){ ? ? ? ? let opts = this.state; ? ? ? ? return ( ? ? ? ? ? ? <div className="dialog-wrap" style={opts.alertStatus ? {display:'block'}:{display:'none'}}> ? ? ? ? ? ? ? ? <div className="dialog-box"> ? ? ? ? ? ? ? ? ? ? <h6>{opts.alertTitle}</h6> ? ? ? ? ? ? ? ? ? ? <p>{opts.alertTip}</p> ? ? ? ? ? ? ? ? ? ? {!opts.isShowCancel && !opts.isShowConfirm ? null : ( ? ? ? ? ? ? ? ? ? ? ? ? <div> ? ? ? ? ? ? ? ? ? ? ? ? ? ? {opts.isShowCancel ? (<span onClick={ () => this.cancel() }>{opts.cancelText}</span>) : null} ? ? ? ? ? ? ? ? ? ? ? ? ? ? {opts.isShowConfirm ? (<span className="confirm" onClick={ () => this.confirm() }>{opts.confirmText}</span>) : null} ? ? ? ? ? ? ? ? ? ? ? ? </div> ? ? ? ? ? ? ? ? ? ? ? ? )} ? ? ? ? ? ? ? ? </div> ? ? ? ? ? ? </div> ? ? ? ? ) ? ? } } ? export default DialogAlert;
這里的數(shù)據(jù)更新用到了componentWillReceiveProps這個生命周期,當(dāng)props發(fā)生變化時執(zhí)行,初始化render時不執(zhí)行,在這個回調(diào)函數(shù)里面,你可以根據(jù)屬性的變化,通過調(diào)用this.setState()來更新你的組件狀態(tài),舊的屬性還是可以通過this.props來獲取,這里調(diào)用更新狀態(tài)是安全的,并不會觸發(fā)額外的render調(diào)用。
調(diào)用頁面index.js
在state中定義可配置字段的變量
import DialogAlert from '../../widget/DialogAlert/index'; ? //省略了組件的js ? this.state = { ? ? dialogOpt:{ ? ? ? ? alertStatus:false, ? ? ? ? alertTip:'我是自定義的內(nèi)容', ? ? ? ? cancelText:'取消2', ? ? ? ? confirmText:'確認(rèn)2', ? ? ? ? isShortTip:false, ? ? ? ? isShowCancel:true, //是否顯示確認(rèn)按鈕 ? ? ? ? isShowConfirm:true, //是否顯示確認(rèn)按鈕 ? ? ? ? cancelCallbackFn:function(){ ? ? ? ? ? alert(0); ? ? ? ? }, //取消 回調(diào)函數(shù) ? ? ? ? confirmCallbackFn:function (){ ? ? ? ? ? alert(1); ? ? ? ? }//確認(rèn) 回調(diào)函數(shù) ? ? ? }, ? ? ? //其他數(shù)據(jù) ? ? };
在jsx中埋好對應(yīng)的組件結(jié)構(gòu)
<div onClick={()=>(this.alertdialog())}>點擊觸發(fā)彈框</div> <DialogAlert dialogOpt={this.state.dialogOpt}></DialogAlert>
添加觸發(fā)事件
alertdialog(){ ? ? let opts = { ? ? ? alertStatus:true ? ? } ? ? let _dialogOpt = Object.assign(this.state.dialogOpt,opts) ? ? this.setState({ ? ? ? dialogOpt:_dialogOpt ? ? }) ? }
這樣就完成一個普通的彈框。總感覺這樣寫的一個組件彈框有點冗余,復(fù)用起來也比較麻煩——在state里配置所有自定義的變量,并改動jsx結(jié)構(gòu),還需要注意寫入jsx結(jié)構(gòu)時彈框的層級問題。
接下來我們來實現(xiàn)一種可動態(tài)調(diào)用的組件:
原理是創(chuàng)建一個div,并插入到body里面,用這個div當(dāng)容器,使用render渲染組件,通過改變組件的state來控制組件的顯示和隱藏。
彈框組件:DialogAlert.js
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import './index.scss'; ? //調(diào)用方法 // DialogAlert.open({ ? ? // alertTitle:'提示2', ? ? // alertTip:"頁面加載失敗,是否重新加載?", ? ? // cancelText:'取消', ? ? // confirmText:'重新加載', ? ? // isShortTip:true, ? ? // isShowCancel:true, ? ? // isShowConfirm:true, ? ? // cancelCallbackFn:function(){ ? ? // ? console.log('取消了') ? ? // }, ? ? // confirmCallbackFn:function (){ ? ? // ? console.log("確認(rèn)了..."); ? ? // } // }); ? class DialogBox extends Component { ? ? constructor(props){ ? ? ? ? super(props); ? ? ? ? this.state = { ? ? ? ? ? ? alertStatus: false, //是否顯示提示框 ? ? ? ? ? ? ? alertTitle:'提示', //標(biāo)題 ? ? ? ? ? ? alertTip:'網(wǎng)絡(luò)錯誤', //提示 ? ? ? ? ? ? cancelText:'取消', ? ? ? ? ? ? confirmText:'確認(rèn)', ? ? ? ? ? ? ? isShortTip:false, //是否為短提示,短提示的情況下不顯示'取消''確認(rèn)'(且2s后消失),且優(yōu)先級最高,其他配置無效 ? ? ? ? ? ? ? isShowCancel:true, //是否顯示確認(rèn)按鈕 ? ? ? ? ? ? isShowConfirm:true, //是否顯示確認(rèn)按鈕 ? ? ? ? ? ? ? cancelCallbackFn:function(){}, //取消 回調(diào)函數(shù) ? ? ? ? ? ? confirmCallbackFn:function (){}//確認(rèn) 回調(diào)函數(shù) ? ? ? ? } ? ? } ? ? ? //打開提示框 ? ? open = (options) => { ? ? ? ? options = options || {}; ? ? ? ?? ? ? ? ? //如果是短提示 ? ? ? ? if(options.isShortTip){ ? ? ? ? ? ? options.isShowCancel = false; ? ? ? ? ? ? options.isShowConfirm = false; ? ? ? ? ? ? setTimeout(()=>{ ? ? ? ? ? ? ? ? this.close() ? ? ? ? ? ? },2000) ? ? ? ? } ? ? ? ? ? options.alertStatus = true; ? ? ? ? this.setState({ ? ? ? ? ? ? ...options ? ? ? ? }) ? ? } ? ? //取消 ? ? cancel = () => { ? ? ? ? this.state.cancelCallbackFn(); ? ? ? ? this.close() ? ? } ? ? //確認(rèn) ? ? confirm = () => { ? ? ? ? this.state.confirmCallbackFn(); ? ? ? ? this.close() ? ? } ? ? close = () => { ? ? ? ? this.setState({ ? ? ? ? ? ? alertStatus:false ? ? ? ? }) ? ? } ? ? ? render(){ ? ? ? ? let opts = this.state; ? ? ? ? return ( ? ? ? ? ? ? <div className="dialog-wrap" style={opts.alertStatus? {display:'block'}:{display:'none'}}> ? ? ? ? ? ? ? ? <div className="dialog-box"> ? ? ? ? ? ? ? ? ? ? <h6>{opts.alertTitle}</h6> ? ? ? ? ? ? ? ? ? ? <p>{opts.alertTip}</p> ? ? ? ? ? ? ? ? ? ? {!opts.isShowCancel && !opts.isShowConfirm ? null : ( ? ? ? ? ? ? ? ? ? ? ? ? <div> ? ? ? ? ? ? ? ? ? ? ? ? ? ? {opts.isShowCancel ? (<span onClick={ () => this.cancel() }>{opts.cancelText}</span>) : null} ? ? ? ? ? ? ? ? ? ? ? ? ? ? {opts.isShowConfirm ? (<span className="confirm" onClick={ () => this.confirm() }>{opts.confirmText}</span>) : null} ? ? ? ? ? ? ? ? ? ? ? ? </div> ? ? ? ? ? ? ? ? ? ? ? ? )} ? ? ? ? ? ? ? ? </div> ? ? ? ? ? ? </div> ? ? ? ? ) ? ? } } ? let div = document.createElement('div'); document.body.appendChild(div); let DialogAlert = ReactDOM.render(<DialogBox /> ,div); //返回實例 ? export default DialogAlert;
調(diào)用頁面index.js
import DialogAlert from '../../widget/DialogAlert/index'; ? ? //省略了組件的js ? DialogAlert.open({ ? ? alertTip:"加載失敗,是否重新加載?", ? ? confirmText:'重新加載', ? ? cancelCallbackFn:()=>{ ? ? ? ? window.history.back(); ? ? }, ? ? confirmCallbackFn:()=>{ ? ? ? ? //todo... ? ? } })
這里用到了ReactDOM.render,官方文檔說這個方法目前會返回了對根組件實例的引用,所以我們可以調(diào)用到里面的open方法。但是官方文檔中目前應(yīng)該避免使用返回的引用,因為它是歷史遺留下來的內(nèi)容。為了以后的react更新迭代的兼容,我們可以省去動態(tài)插入組件的過程,改為寫在jsx中,并設(shè)置ref,使用this.refs.xxx獲取當(dāng)前組件的實例,以便調(diào)用實例方法。
只需引入之后,直接調(diào)用就可以了。這樣寫的好處是解決了彈框的層級問題,也不用去改動jsx結(jié)構(gòu),其他頁面復(fù)用起來更加方便快捷。
這兩種方法在組件的定義上并沒有很大的不同,只是在更新狀態(tài)的時候有差異。第一種方法是在componentWillReceiveProps這個生命周期中監(jiān)聽父組件的值的變化再更新到state上,第二中方法是直接調(diào)用實例的open方法通過獲取參數(shù)將值更新到state上。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
React Native實現(xiàn)進(jìn)度條彈框的示例代碼
本篇文章主要介紹了React Native實現(xiàn)進(jìn)度條彈框的示例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07IntersectionObserver實現(xiàn)加載更多組件demo
這篇文章主要為大家介紹了IntersectionObserver實現(xiàn)加載更多組件demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07詳解Webpack+Babel+React開發(fā)環(huán)境的搭建的方法步驟
本篇文章主要介紹了詳解Webpack+Babel+React開發(fā)環(huán)境的搭建的方法步驟,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01使用react-router4.0實現(xiàn)重定向和404功能的方法
本篇文章主要介紹了使用react-router4.0實現(xiàn)重定向和404功能的方法,具有一定的參考價值,有興趣的可以了解一下2017-08-08React Native之prop-types進(jìn)行屬性確認(rèn)詳解
本篇文章主要介紹了React Native之prop-types進(jìn)行屬性確認(rèn)詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12使用useMutation和React Query發(fā)布數(shù)據(jù)demo
這篇文章主要為大家介紹了使用useMutation和React Query發(fā)布數(shù)據(jù)demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12