当前位置: 首页 > news >正文

二次封装 el-dialog 组件:打造更灵活的对话框解决方案

文章目录

  • 引言
    • 为什么需要二次封装?
    • 封装思路
    • 代码实现
      • 1. 基础封装组件 (Dialog.vue)
      • 2. Vue中引入使用示例
    • 封装后的优势
    • 进阶优化建议
  • 总结


引言

在 Vue 项目中,Element UI 的 el-dialog 是一个非常实用的对话框组件。但在实际开发中,我们经常会遇到需要重复设置对话框属性、处理相同逻辑的情况。通过二次封装,我们可以创建一个更灵活、更易用的对话框组件,提高开发效率并保持代码一致性。

为什么需要二次封装?

  1. 减少重复代码:多个对话框可能需要相同的逻辑(如关闭确认、表单重置等)
  2. 统一风格:确保所有对话框的视觉和交互行为一致
  3. 简化使用:通过默认值和封装方法,减少每次使用时需要编写的代码
  4. 增强功能:添加常用功能如加载状态、国际化支持等

封装思路

我们将创建一个 Dialog 组件,它封装了那些扩展?:

  • 封装了 el-dialog 的常用属性和事件
  • 动态按钮大小,按钮标题动态展示,按钮的type类型
  • 弹窗的动态宽度
  • 是否显示关闭,取消按钮
  • 添加了确认关闭逻辑
  • 支持插槽内容(内容根据项目随意调整)
  • 提供统一的关闭方法
  • 批量按钮的动态添加
  • 窗口的响应式

代码实现

1. 基础封装组件 (Dialog.vue)

<template><div><el-dialogclass="cust-dialog":model-value="show":title="title":width="dialogWidth":top="top + 'px'"@close="close":draggable="true":show-close="showClose":modal-class="'dialog-fade'"><divclass="dialog-body"><slot></slot></div><template #footer><span class="dialog-footer"><slot name="footer"><!-- 默认footer内容 --><el-button type="danger" @click="close" v-if="showCancel">取消</el-button><el-buttonv-for="item in buttons"@click="item.click":type="item.type || primary":size="item.size">{{ item.text }}</el-button></slot></span></template></el-dialog></div>
</template><script setup lang="ts">
import { computed, watch, onMounted, onUnmounted, ref } from "vue";
const props = defineProps<{show: { type: Boolean; default: false };title: { type: String; default: "提示" };width: { type: String; default: "30%" };top: { type: Number; default: 50 };padding: { type: Number; default: 15 };showClose: { type: Boolean; default: true };showCancel: { type: Boolean; default: true };buttons: {type: Array<{text: string;click: () => void;type?: "primary" | "success" | "warning" | "danger" | "info";size?: "large" | "small" | "default";}>;default: () => [];};
}>();const dialogWidth = ref(props.width);
// 监听窗口大小变化,根据窗口宽度动态设置dialog宽度
onMounted(() => {const handleResize = () => {if (window.innerWidth <= 768) {dialogWidth.value = "50%";} else {dialogWidth.value = props.width;}};window.addEventListener("resize", handleResize);
});onUnmounted(() => {window.removeEventListener("resize", handleResize);
});const emit = defineEmits(["close"]);
const close = () => {emit("close");
};
</script><style lang="scss">
@keyframes fade {from {opacity: 0;}to {opacity: 1;}
}.dialog-fade {animation: fade 0.3s;
}.cust-dialog {margin: 30px auto 10px !important;.el-dialog__body {padding: 0px;}.dialog-body {border-top: 1px solid #ddd;border-bottom: 1px solid #ddd;min-height: 80px;overflow: auto;/* 自定义滚动条 */&::-webkit-scrollbar {width: 3px;height: 8px;}&::-webkit-scrollbar-track {background: #f1f1f1;border-radius: 4px;}&::-webkit-scrollbar-thumb {background: #c1c1c1;border-radius: 4px;transition: background 0.3s;&:hover {background: #a8a8a8;}}}.dialog-footer {text-align: right;padding: 5px 20px;}
}
</style>

2. Vue中引入使用示例

<template><div><Dialog:show="dialogConfig.show":title="dialogConfig.title":width="dialogConfig.width":top="dialogConfig.top":padding="dialogConfig.padding":showClose="dialogConfig.showClose":showCancel="dialogConfig.showCancel":buttons="dialogConfig.buttons"@close="dialogConfig.show = false"><el-form :model="form" label-width="auto" style="max-width: 600px"><el-form-item label="Activity name"><el-input v-model="form.name" /></el-form-item><el-form-item label="Activity zone"><el-selectv-model="form.region"placeholder="please select your zone"><el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /></el-select></el-form-item><el-form-item label="Activity time"><el-col :span="11"><el-date-pickerv-model="form.date1"type="date"placeholder="Pick a date"style="width: 100%"/></el-col><el-col :span="2" class="text-center"><span class="text-gray-500">-</span></el-col><el-col :span="11"><el-time-pickerv-model="form.date2"placeholder="Pick a time"style="width: 100%"/></el-col></el-form-item><el-form-item label="Instant delivery"><el-switch v-model="form.delivery" /></el-form-item><el-form-item label="Activity type"><el-checkbox-group v-model="form.type"><el-checkbox value="Online activities" name="type">Online activities</el-checkbox><el-checkbox value="Promotion activities" name="type">Promotion activities</el-checkbox><el-checkbox value="Offline activities" name="type">Offline activities</el-checkbox><el-checkbox value="Simple brand exposure" name="type">Simple brand exposure</el-checkbox></el-checkbox-group></el-form-item><el-form-item label="Resources"><el-radio-group v-model="form.resource"><el-radio value="Sponsor">Sponsor</el-radio><el-radio value="Venue">Venue</el-radio></el-radio-group></el-form-item><el-form-item label="Activity form"><el-input v-model="form.desc" type="textarea" /></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">Create</el-button><el-button>Cancel</el-button></el-form-item></el-form></Dialog><el-button type="primary" @click="showDialog">点击</el-button></div>
</template><script setup lang="ts">
import Dialog from "@/components/Dialog.vue";
import { ref, reactive } from "vue";
const dialogConfig = ref({show: false, // 控制弹窗显示title: "测试弹窗", // 标题width: "80%", // 宽度top: 50, // 距离顶部高度padding: 15, // 内容内边距showClose: true, // 是否显示关闭按钮showCancel: true, // 是否显示取消按钮buttons: [{text: "确定",click: () => console.log("确定"),type: "success",size: "default",},],
});const showDialog = () => {dialogConfig.value.show = true;
};const form = reactive({name: "",region: "",date1: "",date2: "",delivery: false,type: [],resource: "",desc: "",
});const onSubmit = () => {console.log("submit!");
};
</script><style lang="scss" scoped></style>

效果:
在这里插入图片描述

封装后的优势

  1. 统一配置:所有对话框共享相同的配置项,如关闭行为、按钮文本等

  2. 简化使用:只需关注对话框内容,无需重复设置相同属性

  3. 增强功能

    • 内置加载状态
    • 统一的确认/取消逻辑
    • 可选的关闭前确认
  4. 更好的可维护性:所有对话框逻辑集中在一个组件中

  5. 灵活性

    • 保留 el-dialog 的所有属性和事件(通过 $attrs 透传)
    • 支持插槽自定义内容
    • 支持自定义底部按钮

进阶优化建议

  1. 国际化支持:将按钮文本等可配置项提取到语言包中
  2. 主题定制:通过 CSS 变量或 props 允许自定义样式
  3. 动画效果:添加自定义进入/离开动画
  4. 表单验证集成:如果主要用于表单,可以集成表单验证逻辑
  5. 响应式宽度:根据内容自动调整宽度

总结

通过对 el-dialog 的二次封装,我们创建了一个更强大、更易用的对话框组件。这不仅减少了重复代码,还提高了开发效率和代码一致性。在实际项目中,可以根据团队需求进一步扩展这个基础组件,添加更多实用功能。

希望这个封装方案能为你的 Vue 项目开发带来便利!如果你有任何改进建议或使用中的问题,欢迎在评论区交流。

http://www.xdnf.cn/news/430579.html

相关文章:

  • VUE_UI组件的二次封装
  • Redis Cluster 集群搭建和集成使用的详细步骤示例
  • 微信小程序分包策略:优化加载性能与用户体验
  • 使用Kubernetes实现零停机部署
  • android抓包踩坑记录
  • linux系统如何将采集的串口数据存储到txt
  • TCP首部格式及三次握手四次挥手
  • 操作系统导论——第29章 基于锁的并发数据结构
  • 【25软考网工】第六章(5)应用层安全协议
  • 讯联云库项目开发日志(一)
  • 记录算法笔记(2025.5.13)二叉树的最大深度
  • 基于STM32、HAL库的ADAU1701JSTZ-RL音频接口芯片驱动程序设计
  • flink的TaskManager 内存模型
  • 奇怪的公式
  • 代码随想录三十七天 完全背包二维 完全背包一维 518. 零钱兑换 II 377. 组合总和 Ⅳ
  • 视频编解码学习十一之视频原始数据
  • 思维链实现 方式解析
  • Python----神经网络(《Inverted Residuals and Linear Bottlenecks》论文概括和MobileNetV2网络)
  • 简单介绍Qt的属性子系统
  • Python爬虫(26)Python爬虫高阶:Scrapy+Selenium分布式动态爬虫架构实践
  • MLA (Multi-head Attention Layer) 详细说明
  • 报告研读:125页2024年大模型轻量化技术研究报告——技术详细讲解【附全文阅读】
  • 9、Activiti-任务(Task)的相关操作
  • 深入浅出MySQL 8.0:新特性与最佳实践
  • java基础-方法的重写、super关键字
  • NVMe学习资料汇总
  • 浅析AI大模型为何需要向量数据库?从记忆存储到认知进化
  • AI Agent开发第65课-DIFY和企业现有系统结合实现高可配置的智能零售AI Agent(下)
  • 2025年,大模型LLM还有哪些可研究的方向?
  • Mac上安装Mysql的详细步骤及配置