封裝React AntD的dialog彈窗組件
前一段時間分享了基於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 = () => {
// 我是用來重置表單的方法
}
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