• vue3+TS实战中Dialog弹窗封装复用技巧(修改和添加共用一个弹窗)涉及组件的传值(defineProps)和组件的自定义事件(emits)


    前言

    Dialog弹窗在后台管理系统中是使用频率非常高的组件,添加和修改数据基本都会用到,本文就讲讲在vue3和ts的项目中如何封装Dialog组件,实现代码高复用

    在这里插入图片描述

    业务要求

    如下图,在后台管理系统中需要对数据进行添加和编辑,希望他们能共用一个弹窗,那么我们就需要对弹窗的功能进行封装。下面一起来看看在vue3+ts的项目中如何实现:
    在这里插入图片描述

    封装步骤

    对于Dialog组件的封装,我们大致进行如下步骤实现:

    1. 首先实现Dialog组件的UI部分
    2. 点击按钮给组件传入不同的数据,从而判断是编辑功能还是添加功能
    3. 对于不同的功能,请求不同的接口地址

    其中主要的难点在于第二步,涉及组件的传值(defineProps)和组件的自定义事件(emits)。
    下面来分布详细介绍:

    1.Dialog组件的UI部分实现

    我这里使用的是element-plus。
    首先在components文件夹下新建文件DialogModal.vue 用来写这个组件
    UI部分没什么难点,我这里直接贴代码了,根据自己需求进行修改:

    <template>
      <el-dialog
        :before-close="handleClose"
        v-model="show"
        :title="editData ? '编辑收支信息' : '添加收支信息'"
      >
        <el-form
          :model="formData"
          ref="form"
          :rules="formRules"
          label-width="120px"
          style="margin: 10px; width: auto"
        >
          <el-form-item label="收支类型">
            <el-select v-model="formData.type" placeholder="收支类型">
              <el-option
                v-for="(formType, index) in typeList"
                :key="index"
                :label="formType"
                :value="formType"
              ></el-option>
            </el-select>
          </el-form-item>
          <el-form-item prop="describe" label="收支描述">
            <el-input v-model="formData.describe" type="describe"></el-input>
          </el-form-item>
          <el-form-item prop="income" label="收入">
            <el-input v-model="formData.income" type="income"></el-input>
          </el-form-item>
          <el-form-item prop="expend" label="支出">
            <el-input v-model="formData.expend" type="expend"></el-input>
          </el-form-item>
          <el-form-item prop="cash" label="账户现金">
            <el-input v-model="formData.cash" type="cash"></el-input>
          </el-form-item>
          <el-form-item label="备注">
            <el-input v-model="formData.remark" type="textarea"></el-input>
          </el-form-item>
          <el-form-item class="text-right">
            <el-button @click="handleClose">取消</el-button>
            <el-button type="primary" @click="handleSubmit(form)">提交</el-button>
          </el-form-item>
        </el-form>
      </el-dialog>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    有不懂的变量别着急,下面会讲

    2.组件传值和自定义事件

    这里我们按功能分块来讲:

    编辑功能

    首先我们在list页面,

    1. 定义show控制弹窗组件的显示,定义editData存放修改的数据
    const show = ref<boolean>(false);
    const editData = ref<formDataType>()
    
    • 1
    • 2

    这里editData是自定有类型formDataType,从外部ts中引入的类型:

    import { formDataType} from "../utils/types";
    
    • 1

    贴一下这个ts文件的代码:

    export interface formDataType {
        type: string;
        describe: string;
        income: string;
        expend: string;
        cash: string;
        remark: string;
        _id?: string;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 然后给编辑按钮绑定@click="handleEdit(scope.row),然后写这个点击事件:
      控制弹窗显示,然后将点击的当前行数据赋值给 editData
    const handleEdit = (row: formDataType) => {
      show.value = true;
      editData.value = row;
    };
    
    • 1
    • 2
    • 3
    • 4
    1. 在DialogModal组件上绑定传值 show和ditData
    <DialogModal
        :show="show"
        :editData="editData"
    />
    
    • 1
    • 2
    • 3
    • 4

    4.回到DialogModal组件的页面,下面我们要接收传值和监听数据
    这是使用defineProps接受传值:

    const props = defineProps({
      show: {
        type: Boolean,
      },
      editData: {
        type: Object as () => formDataType,
      },
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    我们点击编辑,编辑的弹窗需要显示当前行的数据,所以需要监听传过来的editData,将它赋值给弹窗中的form表单:
    因为props是对象,要监听对象中的数据,所以在watch中使用下面的写法

    watch(
      () => props.editData,
      () => {
        formData.value = props.editData;
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    只有点击编辑按钮,才会传入editData 数据,所以可以通过editData 控制弹窗的title

    <el-dialog
        :before-close="handleClose"
        v-model="show"
        :title="editData ? '编辑收支信息' : '添加收支信息'"
      >
    
    • 1
    • 2
    • 3
    • 4
    • 5
    添加功能和自定义事件
    1. 还是先来到list页面来写添加功能,对于添加功能的点击事件,不需要传数据,只用控制弹窗显示
    const handleAdd = () => {
      show.value = true;
    };
    
    • 1
    • 2
    • 3
    1. 下面我们要实现弹窗关闭的时候的操作,就需要用到自定义事件:
      第一个是@closeModal事件,只需要控制弹窗的show为false关闭弹窗
      第二个是 @handleUpdateProfiles事件,这个事件中需要调用getProfiles();方法
    <DialogModal
        :show="show"
        @closeModal="show = false"
        @handleUpdateProfiles="handleUpdateProfiles"
        :editData="editData"
      />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    getProfiles()方法就是从新获取表格的数据,用于修改或者添加操作完成后刷新数据

    const handleUpdateProfiles = () => {
      getProfiles();
    };
    
    • 1
    • 2
    • 3
    1. 来到DialogModal组建的页面,使用emits处理上面写的自定义事件
    const emits = defineEmits(["closeModal", "handleUpdateProfiles"]);
    
    • 1

    然后需要添加一个dialog的:before-close="handleClose"事件,在关闭弹窗的时候触发事件
    也就是触发自定义的closeModal事件

    const handleClose = () => {
      formData.value = {}
      emits("closeModal");
    };
    
    • 1
    • 2
    • 3
    • 4

    3.不同功能进行不同的api地址请求

    1. 在请求之前,肯定要进行表单的验证:
    const formRules: formRulesType = {
      describe: [{ required: true, message: "收支描述不能为空", trigger: "blur" }],
      income: [{ required: true, message: "收入不能为空", trigger: "blur" }],
      expend: [{ required: true, message: "支出不能为空", trigger: "blur" }],
      cash: [{ required: true, message: "账户现金不能为空", trigger: "blur" }],
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    formRulesType类型也是由自己写的ts文件引入,贴上代码(跟上面使用过的同一文件):

    export interface formRulesType {
        describe: {
            required: boolean;
            message: string;
            trigger: string;
        }[];
        income: {
            required: boolean;
            message: string;
            trigger: string;
        }[];
        expend: {
            required: boolean;
            message: string;
            trigger: string;
        }[];
        cash: {
            required: boolean;
            message: string;
            trigger: string;
        }[];
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    如果表单验证正确,我们就可以进行请求了:
    表单验证的逻辑就不多说了,看重要的url部分,如果props.editData存在,url则为edit/${props.editData._id},不存在则为add。所以后面进行post请求的地址就是/api/profiles/加上url的内容。
    请求完成之后调用自定义事件handleUpdateProfiles和handleUpdateProfiles。刷新表格数据和关闭弹窗

    const handleSubmit = (formEl: FormInstance | undefined) => {
      if (!formEl) return;
      formEl.validate(async (valid: boolean) => {
        if (valid) {
          const url = props.editData?._id ? `edit/${props.editData._id}` : "add";
          await axios.post(`/api/profiles/${url}`, formData.value);
          // @ts-ignore
          ElMessage.success("保存成功");
          emits("handleUpdateProfiles");
          emits("handleUpdateProfiles");
        } else {
        }
      });
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    最后

    到这里我们就完成了整个Dialog弹窗组件的封装,核心就在于通过传值判断是编辑还是添加操作,再通过不同的操作完成不同api的请求。

    在前端开发中创建自定义组件是必不可少的一项基本技能,理解这样的封装思想在实际开发中是很有必要的,可以提高代码重复利用性,减少代码量。

    有疑问欢迎留言交流,批评指正。创作不易,如果对你有帮助 请点赞关注支持下~
    后续会给大家带来更多的优质内容。感谢支持!!!

    在这里插入图片描述

  • 相关阅读:
    记一次.NET某工控图片上传CPU爆高分析
    大漠插件的使用过程(一、插件的注册)
    在优化微信、支付宝小程序用户体验时有哪些关键指标
    李沐深度学习 4.5 权重衰减的知识梳理与课后习题
    [附源码]java毕业设计校园飞毛腿系统
    FFmpeg——使用Canvas录制视频尚存问题的解决方案
    2022-6-29 最大二叉树,根据前序和后序遍历构造二叉树,将子数组重新排序得到同一个二叉查找树的方案数
    Hystrix面试题大全
    ClickHouse快速入门
    连接池-归还连接详解(上)
  • 原文地址:https://blog.csdn.net/weixin_45745641/article/details/126910160