封装React AntD的dialog弹窗组件
前一段时间分享了基于vue和element所封装的弹窗组件(封装Vue Element的dialog弹窗组件),今天就来分享一个基于react和antD所封装的弹窗组件,反正所使用的技术还是那个技术,情况还是那个情况。只是基于vue所封装的弹窗组件和基于react所封装的弹窗组件还是有很大差别的。一样的是封装的思想和思路,不一样的是实现的技术。
至于所用到的技术,还是跟之前分享的有关react组件所用到的技术差不多,无非就是react hooks、函数式组件等。实现思路的话,还是在父组件中打开弹窗,关闭弹窗的操作就交给所封装的弹窗组件,不采用那种所谓的给子组件传一个关闭弹窗的函数,然后让子组件来触发,触发后再由父组件将关闭弹窗的参数传给子组件。这种实现思路可以是可以,就是太绕了,实现起来也麻烦不是?而且每次使用这个弹窗组件时,还得在每个父组件中都写一个关闭弹窗的方法,不累吗?封装的目的是什么?一是统一样式和功能,二是高复用性,三是少写代码,降低开发量,提高开发效率。在我们国家不是有一句很流行的话吗?“让专业的人干专业的事儿”,比如让姚明出任篮协主席,让那个所谓“不懂球的胖子”出任乒协主席,就是这个理儿。
当然有人可能会说如果将关闭弹窗的操作只交给弹窗来做的话,那么万一要在关闭弹窗后再执行某个操作呢,比如弹窗中嵌套了表单组件,如果有表单正则验证没通过,会在表单输入框下边有一个红色的文字提示,此时若关闭弹窗,下次再打开弹窗时会发现那个红色的文字提示还在,这个问题咋解决?总不能在关闭弹窗的函数中加入一个重置表单的方法吧,那如果还有其他需求呢,是不是也要在关闭弹窗的函数中再加入一个方法呢?如果其他需求不需要这样的方法呢?很好,有这样的疑问,说明你考虑问题很全面,哈哈哈哈哈哈,且这样的需求也是实实在在存在的,但依然有很好的解决办法,那就是充分利用弹窗关闭后的回调方法。
关于弹窗关闭后的回调方法,antD和element的弹窗组件都有这个方法,只是element的弹窗组件在关闭后有两个回调:
-
close:Dialog关闭的回调
-
closed:Dialog关闭动画结束时的回调
对于这两个回调,我都拿来试了一把,发现在一般情况下它俩的效果一样,那么官方对第二个回调给的解释是关闭动画结束时的回调,我就有点懵逼了。有兴趣的大佬或已经尝试过的大神别喷我,您就指着我的鼻子,居高临下地告诉我该怎么玩这个就可以了,我会虚心接受的。悄没声地告诉你:element的弹窗组件在关闭的回调中加入重置表单的功能,貌似就无法获取到已修改的表单的值(我是在封装的弹窗组件中嵌套的自己封装的form表单组件,发现在弹窗的关闭回调中去调用嵌套的form组件的重置方法后,获取到的修改的表单的值就变成了上次回显的表单的值,最后我只能把重置表单的功能放在了form组件的mounted生命周期函数中才得以实现。具体实现请移步封装Vue Element的form表单组件),但是antD的弹窗组件就不存在这个问题。
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
作者:小坏
出处:http://tnnyang.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。