封裝React AntD的dialog彈窗元件

小壞先生發表於2020-09-10

前一段時間分享了基於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

相關文章