前一段時間分享了基於vue和element所封裝的彈窗元件(封裝Vue Element的dialog彈窗元件),今天就來分享一個基於react和antD所封裝的彈窗元件,反正所使用的技術還是那個技術,情況還是那個情況。只是基於vue所封裝的彈窗元件和基於react所封裝的彈窗元件還是有很大差別的。一樣的是封裝的思想和思路,不一樣的是實現的技術。
至於所用到的技術,還是跟之前分享的有關react元件所用到的技術差不多,無非就是react hooks、函式式元件等。實現思路的話,還是在父元件中開啟彈窗,關閉彈窗的操作就交給所封裝的彈窗元件,不採用那種所謂的給子元件傳一個關閉彈窗的函式,然後讓子元件來觸發,觸發後再由父元件將關閉彈窗的引數傳給子元件。這種實現思路可以是可以,就是太繞了,實現起來也麻煩不是?而且每次使用這個彈窗元件時,還得在每個父元件中都寫一個關閉彈窗的方法,不累嗎?封裝的目的是什麼?一是統一樣式和功能,二是高複用性,三是少寫程式碼,降低開發量,提高開發效率。在我們國家不是有一句很流行的話嗎?“讓專業的人幹專業的事兒”,比如讓姚明出任籃協主席,讓那個所謂“不懂球的胖子”出任乒協主席,就是這個理兒。
當然有人可能會說如果將關閉彈窗的操作只交給彈窗來做的話,那麼萬一要在關閉彈窗後再執行某個操作呢,比如彈窗中巢狀了表單元件,如果有表單正則驗證沒通過,會在表單輸入框下邊有一個紅色的文字提示,此時若關閉彈窗,下次再開啟彈窗時會發現那個紅色的文字提示還在,這個問題咋解決?總不能在關閉彈窗的函式中加入一個重置表單的方法吧,那如果還有其他需求呢,是不是也要在關閉彈窗的函式中再加入一個方法呢?如果其他需求不需要這樣的方法呢?很好,有這樣的疑問,說明你考慮問題很全面,哈哈哈哈哈哈,且這樣的需求也是實實在在存在的,但依然有很好的解決辦法,那就是充分利用彈窗關閉後的回撥方法。
關於彈窗關閉後的回撥方法,antD和element的彈窗元件都有這個方法,只是element的彈窗元件在關閉後有兩個回撥:
-
close:Dialog關閉的回撥
-
closed:Dialog關閉動畫結束時的回撥
對於這兩個回撥,我都拿來試了一把,發現在一般情況下它倆的效果一樣,那麼官方對第二個回撥給的解釋是關閉動畫結束時的回撥,我就有點懵逼了。有興趣的大佬或已經嘗試過的大神別噴我,您就指著我的鼻子,居高臨下地告訴我該怎麼玩這個就可以了,我會虛心接受的。
antD在關閉彈窗後也給了一個回撥afterClose,官方的解釋是Modal完全關閉後的回撥,但人家就只給了這一個關閉後的回撥。好吧,就這個回撥已經足夠我們實現我們的需求了。我們把那些需要在關閉彈窗後再做的一些事情都放在這個回撥中,然後把這個回撥從父元件再傳給所封裝的彈窗子元件就完事了。如果你不傳,代表你沒有這方面的需求,對彈窗的正常工作又沒有絲毫的影響,這豈不是很香嗎?
說了這麼多,光說不練假把式,那就來看具體實現唄。
照例還是先來張效果圖:
1、所封裝的彈窗元件dialog.js
import React, { useState, useImperativeHandle } from 'react'
import PropTypes from 'prop-types'
import { Modal } from 'antd';
let ok = () => {};
const DialogCom = ({btnTxt = ['取消', '確定'], children, cRef, autoClose = true, ...reset}) => {
const [visible, setVisible] = useState(false);
const open = cb => {
setVisible(true);
ok = cb;
}
useImperativeHandle(cRef, () => ({
open: cb => open(cb),
}));
const handleCancel = () => {
setVisible(false);
}
const handleOk = () => {
autoClose && setVisible(false);
ok(handleCancel);
}
return <Modal
{...reset}
maskClosable={false}
visible={visible}
onOk={handleOk}
onCancel={handleCancel}
okText={btnTxt[1]}
cancelText={btnTxt[0]}
>
{children}
</Modal>
}
DialogCom.propTypes = {
btnTxt: PropTypes.array,
children: PropTypes.any.isRequired,
cRef: PropTypes.object.isRequired,
autoClose: PropTypes.bool,
}
export default DialogCom
以上程式碼中的具體實現思路這裡就不再做過多的介紹了,可以移步封裝Vue Element的dialog彈窗元件這裡。封裝Vue Element的dialog彈窗元件這篇博文已經對實現的思路做了詳細的介紹了。
2、使用方法:
import React, { useRef } from 'react'
import { Button } from 'antd';
import Dialog from './dialog'
const DialogDemo = () => {
const childRef = useRef();
const open = () => {
childRef.current.open(cancel => {
// cancel();
console.log('開啟')
});
}
const resetForm = () => {
console.log('重置表單')
}
const config = {
title: '提示',
btnTxt: ['關閉', '提交'],
centered: true,
width: '400px',
afterClose: resetForm, // Modal完全關閉後的回撥
}
return <>
<Button type="primary" onClick={open}>開啟彈窗</Button>
<Dialog {...config} cRef={childRef}>
<p>我是彈窗</p>
<p>我是彈窗</p>
</Dialog>
</>
}
export default DialogDemo
使用方法中的程式碼這裡也不再做介紹了,封裝Vue Element的dialog彈窗元件這篇博文也介紹的很詳細了。
最後還是再貼一下本次封裝所用到的各個包的版本:
react: 16.8.6,
react-dom: 16.8.6,
react-router-dom: 5.0.0,
antd: 4.3.5,
@babel/core: 7.4.4,
babel-loader: 8.0.5