封装一个可以最小化和展开的弹窗组件

ops/2024/9/23 14:33:55/

gl-dialog

大概思路:
在弹窗组件内部引入gl-dialog-collapse,这个组件主要用于存储已经被最小化的弹窗(基础数据)
弹窗内部的数据如何在父组件拿到是通过作用域插槽来实现的
gl-dialog接收一个tempData这个数据会在内部被记录下来,然后通过插槽的形式传递给父组件,供父组件使用
在这里插入图片描述

<template><div class="gl-dialog" ref="dialogRef"><el-dialog:close-on-click-modal="false"v-bind="$attrs":visible.sync="selfVisible":show-close="false"><div class="dialog-header" slot="title"><div class="left-title">{{ currentData.dialogTitle }}</div><div class="right-icon"><ititle="缩小"class="iconfont icon-segi-icon-minus"style="font-size: 14px"@click="toCollapse"></i><ititle="关闭"class="iconfont icon-Close"style="font-size: 14px;font-weight: bold;"@click="closeDialog"></i></div></div><slot :tempData="currentData"></slot><footer><slot name="footer" :tempData="currentData" /></footer></el-dialog><gl-dialog-collapse :dialogList="dialogList"></gl-dialog-collapse></div>
</template><script>
import _ from "lodash";
export default {name: "gl-dialog",props: {visible: {type: Boolean,default: () => false,},title: String,type: {type: String,default: () => "default",},tempData: Object,},data() {return {ddd: "okok",dialogList: [],currentData: {},count: 0,isExpand: false,// dialogId: "",};},computed: {dialogId() {return this.tempData.dialogTitle + this.count;},selfVisible: {get() {return this.visible;},set(value) {this.$emit("update:visible", value);},},},watch: {visible(N) {if (N) {if (!this.isExpand) {this.currentData = _.cloneDeep(this.tempData);this.currentData.dialogTitle = this.title;this.currentData.dialogId = this.dialogId;} else {this.count++;}}},},methods: {toCollapse() {const targetIndex = this.dialogList.findIndex((item) => {const { dialogId } = this.currentData;return dialogId == item.dialogId;});const isExist = targetIndex >= 0;if (!isExist) {this.dialogList.push({type: this.type,title: this.currentData.dialogTitle,dialogId: this.dialogId,tempData: this.currentData,expandCallBack: (tempData) => {this.isExpand = true;this.currentData = tempData;this.currentData.dialogId = tempData.dialogId;this.selfVisible = true;},});this.count++;}this.isExpand = false;this.selfVisible = false;},closeDialog() {this.isExpand = false;this.selfVisible = false;if (!this.dialogList.length) return;const targetIndex = this.dialogList.findIndex((item) => {const dialogId = this.isExpand? this.currentData.dialogId: this.dialogId;return dialogId == item.dialogId;});if (targetIndex >= 0) {this.dialogList.splice(targetIndex, 1);}},},
};
</script><style lang="scss" scoped>
.dialog-header {display: flex;align-items: center;justify-content: space-between;
}
// ::v-deep .dialog-footer {
//   text-align: right!important;
// }
.iconfont {cursor: pointer;
}
footer {text-align: right;
}
</style>

gl-dialog-collapse.vue

<template><div class="gl-dialog-collapse"><div class="collapse-item" v-for="(item, index) in dialogList" :key="index"><div class="title">{{ item.title }}</div><div class="right-icons"><ititle="放大"class="iconfont icon-icf_full_screen_arrow"@click="toExpand(item)"></i><i title="关闭" class="iconfont icon-Close" @click="closeDialog"></i></div></div></div>
</template><script>
export default {name: "gl-dialog-collapse",props: {dialogList: {type: Array,default: [],},},methods: {toExpand(item) {const { expandCallBack, tempData } = item;expandCallBack(tempData);this.closeDialog(item);},closeDialog(item) {const { dialogId } = item;const targetIndex = this.dialogList.findIndex((item) => item.dialogId == dialogId);this.dialogList.splice(targetIndex, 1);},},
};
</script><style lang="scss" scoped>
.gl-dialog-collapse {display: flex;column-gap: 5px;position: fixed;left: 201px;bottom: 0px;
}
.collapse-item {padding: 5px 10px;display: flex;align-items: center;column-gap: 20px;border: 1px solid #ccc;background-color: #fff;.title {font-size: 14px;}
}
.right-icons {i {cursor: pointer;font-size: 16px;}
}
</style>

实现效果:
在这里插入图片描述
在这里插入图片描述
每个最小化的弹窗内部数据都是独立的,因为gl-dialog-collapse内部维护了一个已经被折叠的弹窗数组。
内部的数据结构:

{type: this.type,title: this.currentData.dialogTitle,dialogId: this.dialogId,tempData: this.currentData,expandCallBack: (tempData) => {this.isExpand = true;this.currentData = tempData;this.currentData.dialogId = tempData.dialogId;this.selfVisible = true;},}

dialogId用于记录唯一弹窗,方便回显数据,以及关闭目标弹窗

反思:当时考虑用cloneNode来实现弹窗的复制,但是考虑到vue里面是通过数据来驱动视图,能够成功复制弹窗,但是里面的交互会失效,所以感觉这种方案会很复杂,所以放弃。中途参考过layui弹窗最小化的实现方式,发现是对节点进行克隆,所以每最小化一个弹窗就会多产生一个节点。


http://www.ppmy.cn/ops/38589.html

相关文章

水平滑动与垂直滑动菜单

水平滑动菜单 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>*{margin: 0;padding: 0;}ul{background-color: #000;}ul li{text-shadow: none;display: inline-block;height: 40px;}ul li a{…

Linux流量分析工具 | nethogs

在应急过程中&#xff0c;经常会遇到应用访问缓慢&#xff0c;网络阻塞的情况&#xff0c;分析原因可能会想到存在恶意程序把带宽占满的可能。通过这样一个小工具可以快速定位异常占用带宽程序的路径、PID、占用流量大小或是排除由带宽占满导致服务器缓慢的猜想。 一、简介 Ne…

ARM(4)缓存一致性

目录 一、缓存一致性问题 二、一致性实现方案 2.1 目录一致性协议 2.2 嗅探一致性协议 三、CHI协议 3.1 cache state 3.2 snoop维护一致性 四、其他一致性协议 4.1 MSI协议 4.2 MESI 协议 4.3 MOESI协议 本文介绍以下内容&#xff1a; 缓存一致性问题一致性实现方案…

崇贸烧录器支持PUYA普冉半导体的32位微控制器PY32F403R1DT6

芯片烧录行业领导者-崇贸技术近日发布最新的烧录软件更新及新增支持的芯片型号列表&#xff0c;其中PUYA普冉半导体的32位微控制器PY32F403R1DT6已经被崇贸的通用烧录平台AP8000所支持。 PY32F403R1DT6微控制器是基于ArmCortexM4核的32位通用微控制器产品。内置的FPU和DSP功能…

视频监控平台:交通运输标准JTT808设备SDK接入源代码函数分享

目录 一、JT/T 808标准简介 &#xff08;一&#xff09;概述 &#xff08;二&#xff09;协议特点 1、通信方式 2、鉴权机制 3、消息分类 &#xff08;三&#xff09;协议主要内容 1、位置信息 2、报警信息 3、车辆控制 4、数据转发 二、代码和解释 &#xff08;一…

计算机网络——Dijkstra路由算法

实验目的 实现基于 Dijkstra 算法的路由软件 实验内容 网络拓扑如图所示 实验过程 先编写开辟应该图的空间&#xff0c;然后给点映射数字&#xff0c;构建图。程序获取用户输入的学号&#xff0c;构建图中边的权值。接下来程序从用户输入获取最短路径的搜索起点&#xff0…

.net 6.0 框架集成ef实战,步骤详解

一、代码框架搭建 搭建如下代码架构&#xff1a; 重点含EntityFrameworkCore工程&#xff0c;该工程中包含AppDbContext.cs和数据表实体AggregateObject 1、AppDbContext 代码案例 //AppDbContext 代码案例using Microsoft.EntityFrameworkCore;namespace EntityFrameworkCo…

Spring Security 入门 2

1.项目实战 就以RuoYi-Vue 为例吧&#xff0c;主要以下几点原因&#xff1a; 基于 Spring Security 实现。 基于 RBAC 权限模型&#xff0c;并且支持动态的权限配置。 基于 Redis 服务&#xff0c;实现登录用户的信息缓存。 前后端分离。同时前端采用 Vue &#xff0c;相对来…