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>

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

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

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

编辑功能

首先我们在list页面,

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

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

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

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

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

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

const props = defineProps({
    
    
  show: {
    
    
    type: Boolean,
  },
  editData: {
    
    
    type: Object as () => formDataType,
  },
});

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

watch(
  () => props.editData,
  () => {
    
    
    formData.value = props.editData;
  }
);

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

<el-dialog
    :before-close="handleClose"
    v-model="show"
    :title="editData ? '编辑收支信息' : '添加收支信息'"
  >

添加功能和自定义事件

  1. 还是先来到list页面来写添加功能,对于添加功能的点击事件,不需要传数据,只用控制弹窗显示
const handleAdd = () => {
    
    
  show.value = true;
};
  1. 下面我们要实现弹窗关闭的时候的操作,就需要用到自定义事件:
    第一个是@closeModal事件,只需要控制弹窗的show为false关闭弹窗
    第二个是 @handleUpdateProfiles事件,这个事件中需要调用getProfiles();方法
<DialogModal
    :show="show"
    @closeModal="show = false"
    @handleUpdateProfiles="handleUpdateProfiles"
    :editData="editData"
  />

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

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

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

const handleClose = () => {
    
    
  formData.value = {
    
    }
  emits("closeModal");
};

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" }],
};

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;
    }[];
}

如果表单验证正确,我们就可以进行请求了:
表单验证的逻辑就不多说了,看重要的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 {
    
    
    }
  });
};

最后

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

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

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

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45745641/article/details/126910160