在 VueJS 项目中实现多个可拖拽的弹出框(多个可拖拽el-dialog弹出框,共用同一函数)

news2024/11/15 13:42:02

前言

在项目开发中,弹出框(Dialog)是常见的UI组件。默认情况下,弹出框的位置是固定的,但在某些场景下,我们希望用户可以自由拖动弹出框的位置,以提升用户体验。之前单个视频拖拽弹框,已经介绍过了,详细请看:

单个视频拖拽弹框icon-default.png?t=N7T8https://blog.csdn.net/weixin_65793170/article/details/140274477?spm=1001.2014.3001.5502

这里将详细介绍一下,如何通过创建一个 Vue mixins,实现多个可拖拽的弹出框功能。为了使多个弹窗都能独立地实现拖拽功能,你需要确保每个弹窗都有自己的拖拽逻辑。在 Vue 中,你可以通过将拖拽逻辑抽象成一个可复用的混入 mixins 来实现这一目标。这里来记录一下


一. 创建 Draggable.JS

1. 首先,我们创建一个可复用的 mixin 文件 draggable.js ,用于实现弹出框的拖拽功能,详细请看以下

// src/mixins/draggable.js
export default {
    // 在组件挂载后初始化拖拽功能
    mounted() {
        // 确保 DOM 更新完成后调用 initDraggable 方法
        this.$nextTick(() => {
            this.initDraggable();
        });
    },
    methods: {
        // 初始化拖拽功能
        initDraggable() {
            // 查找所有 el-dialog 元素
            const dialogs = this.$el.querySelectorAll('.el-dialog');
            // 为每个 el-dialog 元素添加拖拽功能
            dialogs.forEach(dialog => {
                this.makeDraggable(dialog);
            });
        },
        // 实现拖拽功能
        makeDraggable(dragDom) {
            // 设置初始样式:居中并清除 margin
            dragDom.style.cssText += `
                margin: 0 !important;
                position: absolute !important;
                top: 50% !important;
                left: 50% !important;
                transform: translate(-50%, -50%) !important;
            `;
            // 设置鼠标样式为移动光标
            dragDom.style.cursor = 'move';

            // 获取元素的样式属性
            const getStyle = (dom, attr) => getComputedStyle(dom, false)[attr];

            // 鼠标按下事件处理器
            const mousedownHandler = (e) => {
                // 检查是否点击了不应该触发拖拽的元素
                if (e.target.tagName === 'INPUT' ||
                    e.target.tagName === 'TEXTAREA' ||
                    e.target.tagName === 'SELECT' ||
                    e.target.tagName === 'BUTTON' ||
                    e.target.closest('.el-dialog__footer')) {
                    return;
                }

                // 阻止默认行为
                e.preventDefault();

                // 获取弹出框的位置和鼠标点击位置的偏移量
                const dialogRect = dragDom.getBoundingClientRect();
                const disX = e.clientX - dialogRect.left;
                const disY = e.clientY - dialogRect.top;

                // 获取屏幕的宽高
                const screenWidth = document.documentElement.clientWidth;
                const screenHeight = document.documentElement.clientHeight;

                // 移除初始的居中样式
                dragDom.style.left = `${dialogRect.left}px`;
                dragDom.style.top = `${dialogRect.top}px`;
                dragDom.style.transform = 'none';

                // 鼠标移动事件处理器
                const mouseMoveHandler = (e) => {
                    // 计算弹出框的新位置
                    let left = e.clientX - disX;
                    let top = e.clientY - disY;

                    // 边界检查,防止弹出框移出屏幕
                    left = Math.min(Math.max(left, 0), screenWidth - 
dialogRect.width);
                    top = Math.min(Math.max(top, 0), screenHeight - 
dialogRect.height);

                    // 设置弹出框的新位置
                    dragDom.style.left = `${left}px`;
                    dragDom.style.top = `${top}px`;
                };

                // 鼠标松开事件处理器
                const mouseUpHandler = () => {
                    // 移除事件监听器
                    document.removeEventListener('mousemove', mouseMoveHandler);
                    document.removeEventListener('mouseup', mouseUpHandler);
                };

                // 添加事件监听器
                document.addEventListener('mousemove', mouseMoveHandler);
                document.addEventListener('mouseup', mouseUpHandler);
            };

            // 为整个弹出框添加鼠标按下事件监听器
            dragDom.addEventListener('mousedown', mousedownHandler);
        }
    }
};};

2. 过程概述

  1. 组件挂载时初始化拖拽:当组件完成挂载并DOM更新后,mounted钩子会调用initDraggable方法,这个方法负责找到页面上的所有el-dialog元素,并为它们分别调用makeDraggable方法。

  2. 使元素可拖动makeDraggable方法接收一个DOM元素作为参数,它首先设置元素的CSS样式以使其可以被拖动。然后,它添加了一个mousedown事件监听器,以便在用户点击对话框时开始拖动过程。

  3. 处理鼠标按下事件mousedownHandler函数检查是否点击了不应该触发拖拽的元素,如输入框、文本区域、选择框、按钮或对话框的底部。如果是,则返回而不做任何操作。如果点击的是可拖动区域,它阻止了默认的鼠标行为,计算了对话框相对于鼠标点击位置的偏移量,并记录了屏幕的尺寸。

  4. 拖动过程中:当mousedown事件触发后,添加了mousemovemouseup事件监听器。mousemove事件用于实时更新对话框的位置,同时进行边界检查,以防止对话框移出屏幕。mouseup事件则用于结束拖动过程,移除相关事件监听器。

3. 注意事项

  1. 避免覆盖内部元素:在拖动过程中,需要确保对话框不会覆盖其内部的输入字段等交互元素。为此,在mousedownHandler中检查了目标元素的类型,并在必要时停止拖动。

  2. 样式覆盖为了使对话框可拖动,使用了!important来确保样式更改优先级高于任何其他可能的CSS规则。然而,过度使用!important可能导致难以预料的样式冲突,因此在生产环境中应谨慎使用。

  3. 性能与兼容性直接操作DOM样式可能会导致重绘和重排,影响性能。此外,不同的浏览器可能有不同的实现细节,因此需要测试以确保跨浏览器的兼容性和一致性。

  4. 事件监听器管理:在拖动结束后,必须正确地移除事件监听器,否则可能导致内存泄漏。mouseUpHandler函数负责清理这些监听器。

  5. 用户界面反馈虽然代码中设置了鼠标光标为移动图标,但为了增强用户体验,还可以考虑在拖动过程中提供视觉反馈,例如改变背景色或边框样式。


二. 在组件中引用 Draggable.JS,并使用 Mixins 挂载

这里,在需要实现,可拖拽功能的组件中引用 draggable.js,并将其应用到 el-dialog 组件中

// 引入 draggable ,mixin 挂载
import draggable from "@/mixins/draggable.js";  

export default {
    mixins: [draggable],  // 使用 mixin
};};


三. 使用可拖拽对话框

1. 这里,在组件模板部分,我们添加了三个 el-dialog 组件,并应用了可拖拽的 mixin。每个对话框的 title、visible、before-close 等属性根据具体需求设置

<template>
    <!--弹出框1 -->
    <el-dialog
      title="事件1"  // 对话框标题
      :visible.sync="dialogVisible"  // 控制对话框的显示状态
      width="30%"  // 对话框宽度
      :before-close="handleClose"  // 关闭对话框前的回调
      :modal="false"  // 禁用模态背景
      :close-on-click-modal="false"  // 禁用点击模态背景关闭对话框
      class="cesium_dialog"
    >
      <flvVue :Url="Your_Url1"></flvVue>  // 实时视频播放组件
      <span slot="footer" class="dialog-footer"></span>  // 对话框底部空白占位
    </el-dialog>

    <!--弹出框2 -->
    <el-dialog
      title="事件2"  // 对话框标题
      :visible.sync="dialogVisible2"  // 控制对话框的显示状态
      width="30%"  // 对话框宽度
      :before-close="handleClose2"  // 关闭对话框前的回调
      :modal="false"  // 禁用模态背景
      :close-on-click-modal="false"  // 禁用点击模态背景关闭对话框
      class="cesium_dialog"
    >
      <video src="Your_Url2" controls></video>  // 视频播放组件
      <span slot="footer" class="dialog-footer"></span>  // 对话框底部空白占位
    </el-dialog>

    <!-- 弹出框3 -->
    <el-dialog
      title="事件3"  // 对话框标题
      :visible.sync="dialogVisible3"  // 控制对话框的显示状态
      width="30%"  // 对话框宽度
      :before-close="handleClose3"  // 关闭对话框前的回调
      :modal="false"  // 禁用模态背景
      :close-on-click-modal="false"  // 禁用点击模态背景关闭对话框
      class="cesium_dialog"
    >
      <video
        src="Your_Url3"
        controls
      ></video>  // 视频播放组件
      <span slot="footer" class="dialog-footer"></span>  // 对话框底部空白占位
    </el-dialog>
</template>

<script>
import draggable from "@/mixins/draggable.js";  // 引入 draggable mixin

export default {
    mixins: [draggable],  // 使用 mixin
    data() {
        return {
            dialogVisible: false,  // 控制第一个弹出框的显示
            dialogVisible2: false,  // 控制第二个弹出框的显示
            dialogVisible3: false,  // 控制第三个弹出框的显示
            rtsp2: 'http://your_rtsp_url'  // 实时视频播放的 URL
        };
    },
    methods: {
        handleClose() {
            this.dialogVisible = false;  // 关闭第一个弹出框
        },
        handleClose2() {
            this.dialogVisible2 = false;  // 关闭第二个弹出框
        },
        handleClose3() {
            this.dialogVisible3 = false;  // 关闭第三个弹出框
        },
        DialogOpen(flag, text) {
            // 根据 flag 值打开相应的弹出框
            if (flag === 1) {
                this.dialogVisible = true;
            } else if (flag === 2) {
                this.dialogVisible2 = true;
            } else if (flag === 3) {
                this.dialogVisible3 = true;
            }
        }
    }
};};
</script>

2. 过程概述

  1. 弹出框配置:每个el-dialog都有其标题、宽度、可见性绑定、关闭前回调等配置。特别地,禁用了模态背景和点击模态背景关闭对话框的行为,允许用户在弹出框打开时仍能与页面其他部分交互。

  2. 视频播放:弹出框内嵌入了视频播放组件或原生的<video>标签,源地址由Your_Url1, Your_Url2, 和 Your_Url3变量指定。

  3. 混入Draggable功能:通过引入draggable.js混入,使得弹出框能够被拖动。这在组件初始化时自动应用,无需额外的配置。

  4. 数据和方法:定义了控制弹出框可见性的数据属性以及关闭弹出框的方法。DialogOpen方法可以根据传入的flag值打开特定的弹出框。

3. 注意事项

  • 资源加载:确保视频资源URL有效且可访问,尤其是对于实时流,需要确认流服务器正常工作。

  • 权限问题:如果视频源来自跨域,需要确保服务器支持CORS(跨源资源共享),否则视频可能无法加载。

  • 响应式设计:虽然弹出框宽度固定为30%,但在不同屏幕尺寸上可能需要进一步优化布局,以适应不同设备。

  • 性能考虑:同时播放多个视频可能对系统资源造成压力,特别是在资源受限的设备上。

  • 用户交互:由于弹出框没有模态背景,应确保用户能够清晰地区分焦点,避免混淆。

  • 代码维护性如果弹出框具有相似的结构和功能,考虑将其抽象为一个可复用的组件,减少代码冗余。


四. 必要的 CSS

/* 确保对话框内的视频占满对话框宽度并设置高度 */
::v-deep .cesium_dialog video {
  width: 100%;
  height: 300px;
}

/* 禁用对话框遮罩层的点击事件 */
::v-deep .el-dialog__wrapper {
  pointer-events: none !important;
}

/* 允许对话框内的元素进行交互,并设置对话框距离顶部的距离 */
::v-deep .el-dialog__wrapper .el-dialog {
  pointer-events: auto !important;
  margin-top: 20vh !important;
}


五. 本章总结

在以上内容中,我们探讨了如何在Vue.js应用程序中使用Element UI的el-dialog组件创建多个可拖动的对话框,同时讨论了如何优化代码结构和事件处理。

1. 主要内容概览

  1. Draggable Mixin: 提供了一个Vue.js mixin,名为draggable.js,用于使多个el-dialog对话框可拖动。这个mixin在组件挂载后初始化拖拽功能,通过查找所有.el-dialog元素并为它们添加拖拽逻辑。拖拽功能包括设置初始样式、处理鼠标按下、移动和释放事件,以及限制对话框在屏幕内的移动范围。

  2. Dialog Components: 展示了三个el-dialog对话框实例,分别用于显示不同的视频内容。每个对话框都配置了标题、宽度、关闭前回调、以及关闭时的行为。对话框被赋予了相同的类名cesium_dialog,这表明它们共享某些样式或功能。

  3. Visibility Control: 为每个对话框定义了visible.sync属性,用于控制对话框的显示状态。同时,还定义了handleClose, handleClose2, 和 handleClose3方法,用于关闭各自的对话框。

2. 结论

通过使用提供的draggable mixin,我们可以轻松地使多个el-dialog组件具备拖拽功能,从而提高用户界面的交互性。同时,通过重构和优化事件处理逻辑,可以减少代码冗余,提高代码的可读性和可维护性。此外,可以直接在对话框组件上,添加外层元素实现事件委托,在其父容器上实施事件监听和逻辑处理是一种实用的替代方案。 

创作不易,感觉有用,就一键三连,感谢(●'◡'●)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1974114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot 参数校验 Validation 使用

概述 当我们想提供可靠的 API 接口&#xff0c;对参数的校验&#xff0c;以保证最终数据入库的正确性&#xff0c;是必不可少的活。前、后端校验都是保证参数的准确性的手段之一&#xff0c;前端校验并不安全&#xff0c;任何人都可以通过接口来调用我们的服务&#xff0c;就算…

springboot电影购票系统-计算机毕业设计源码85384

目录 摘要 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1系统开发流程 2.2.2 用户登录流程 2.2.3 系统操作流程 2.2.4 添加信息流程 2.2.5 修改信息流程 2.2.6 删除信息流程 2.3 系统功能…

ComfyUI插件:ComfyUI layer style 节点(三)

前言&#xff1a; 学习ComfyUI是一场持久战&#xff0c;而ComfyUI layer style 是一组专为图片设计制作且集成了Photoshop功能的强大节点。该节点几乎将PhotoShop的全部功能迁移到ComfyUI&#xff0c;诸如提供仿照Adobe Photoshop的图层样式、提供调整颜色功能&#xff08;亮度…

哪里可以找到数据恢复软件?5 款顶级数据恢复软件分享

在当今的数字时代&#xff0c;我们的数据既是我们最宝贵的资产&#xff0c;也是我们最大的弱点。由于硬件故障、意外删除或软件问题&#xff0c;丢失重要文档、珍贵照片或对职业至关重要的项目的风险始终存在。值得庆幸的是&#xff0c;强大的数据恢复软件可以帮助找回最初看似…

[每周一更]-(第108期):如何保护你的JavaScript代码

文章目录 一、框架如何实现JS的保护1. 模块化和组件化2. 使用环境变量3. 代码混淆和最小化vue.config.js 4. 使用请求库和拦截器axios.js 文件在组件中使用 Axios 拦截器 5. 服务端处理敏感逻辑6. 安全最佳实践使用 CSP 7. 依赖前端框架的内置安全特性8. 数据验证和清理 二、原…

【linux】【操作系统】内核之traps.c源码阅读

C 文件traps.c 是 Linux 内核的一部分&#xff0c;主要处理硬件陷阱和故障。文件中包含多个函数来处理不同类型的异常和错误。下面是详细的解析&#xff1a; 概览 目的&#xff1a;此文件负责处理各种硬件异常和故障。它包括了处理特定类型错误以及初始化异常处理器的函数。文…

uniapp0基础编写安卓原生插件和调用第三方jar包(Ch34的jar包)和如何解决android 如何Application初始化

前言 我假设你会uniapp安卓插件开发了,如果不会请看这篇文章,这篇文章是0基础教学。 这篇文章我们将讲一下如何使用CH34XUARTDriver.jar进行开发成uniapp插件。 它的难点是:uniapp如何Application初始化第三方jar包 先去官网下载CH340/CH341的USB转串口安卓免驱应用库:h…

Spring实现自定义注解

一&#xff0c; 背景 目前部门有一个培训&#xff0c;需要讲一下Spring的使用&#xff0c;看到有同学提出问题&#xff0c;想自定义实现一个打日志的注解&#xff0c;下面就记录一下实现过程。 环境&#xff1a; Spring 6.1.5, 不使用Spring Boot. 二&#xff0c;实现步骤 …

Mysql--权限与安全管理

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、权限表 MySQL服务器通过权限表来控制用户对数据库的访问&#xff0c;权限表存放在MySQL数据库中&#xff0c;由MySQL_install_db脚本初始化。存储…

【工具篇】华为VRP通用操作系统 —— 配置文件管理

文章目录 配置文件分类配置文件命令配置文件工作原理 配置文件分类 设备的配置文件通常有两种类型&#xff1a; 1、启动配置文件&#xff08;Startup Configuration&#xff09;&#xff1a; 这是设备启动时加载的配置文件&#xff0c;包含了设备的基本配置信息&#xff0c;如…

Linux 内核源码分析---资源分配及系统总线

资源管理 Linux提供通用的构架&#xff0c;用于在内存中构建数据结构。这些结构描述了系统中可用的资源&#xff0c;使得内核代码能够管理和分配资源。 其中关键的数据结构resource如下&#xff1a; 用于连接parent, child, sibling成员规则如下&#xff1a; 1、每个子结点只…

接口测试学习笔记1

一、行业背景和测试分层 1、招聘需求 1&#xff09;手工测试&#xff1a;业务需求、业务逻辑 2&#xff09;自动化测试&#xff1a;业务逻辑 技术规范 功能自动化 QTP、Selenium 性能自动化 LoadRunner、JMeter 接口自动化 Postman、Fiddler、JMeter、SoapUI... …

值得一读!六本网络安全学习必备书籍推荐

在网络安全领域不断发展的今天&#xff0c;深入学习和掌握相关知识显得尤为重要。以下为大家推荐六本有助于提升网络安全技能的经典书籍。 一、《白帽子讲 Web 安全》 这本书由吴翰清撰写&#xff0c;涵盖了 Web 安全的诸多方面&#xff0c;包括常见的攻击手段、防御方法以及安…

XML 学习笔记

简介&#xff1a; &#xff08;1&#xff09;XML&#xff1a;可扩展性标记语言&#xff0c;用于传输和存储数据&#xff0c;而不是展示数据&#xff0c;是W3C 推举的数据传输格式。 XML的标签必须自定义&#xff0c;但是在写标签名的时候一定要有含义。 XML 只能有一个根节点…

微积分-微分应用7(优化问题)

解决优化问题的步骤&#xff1a; 理解问题 首先要仔细阅读问题&#xff0c;直到完全理解。问问自己&#xff1a;未知数是什么&#xff1f;已知量是什么&#xff1f;给定的条件是什么&#xff1f; 画图 在大多数问题中&#xff0c;画图并在图中标出给定和所需的量是有用的。 引…

用闲置的阿里云服务器使用 NPS 实现内网穿透

最近有个项目需要给外地的同事预览一下&#xff0c;但是公司没有可以公网访问的测试服务器&#xff0c;所以想到用内网穿透的方式让外地同事可以访问到我的本机。刚好我有一台阿里云的服务器&#xff0c;双十一打折买了3年&#xff0c;1000左右&#xff0c;2核8G&#xff0c;买…

24年税务师考试补报名即将开始啦

⏰税务师补报名重要时间节点 1⃣️补报名时间&#xff1a;8月6日10:00至8月16日17:00 2⃣️补报名缴费时间&#xff1a;8月6日10:00至8月18日24&#xff1a;00 3️⃣准考证打印时间&#xff1a;10月28日10:00至11月3日15:00 4⃣️考试时间&#xff1a;11月2日、3日 ✅税务…

c#中的BitConverter的java实现

最近在做c#项目的java迁移&#xff0c;发现部分C#方法java中没有对应实现如图&#xff1a; 且java中的数字类型都是有符号的所以转无符号的时候需要进行手动对符号位& 0xFFFF进行处理&#xff0c;目前只整理了项目中使用到的方法&#xff0c;后续有用到其他方法在进行追加如…

HarmonyOS 与 OpenHarmony 的区别详解

随着科技的不断进步&#xff0c;操作系统在我们日常生活中的重要性日益凸显。华为推出的 HarmonyOS 和 OpenHarmony 正是当前备受关注的两大操作系统。它们虽然紧密相关&#xff0c;但在理念、目标和应用场景上有显著的区别。本文将详细探讨这两者的不同之处。 一、概念解析 …

C++复习的长文指南(二)

C复习的长文指南&#xff08;二&#xff09; 一、面向对象基础知识5. 文件操作5.1文本文件5.1.1写文件5.1.2读文件 5.2 二进制文件5.2.1 二进制文件5.2.2 二进制读文件 6. c面向对象的个人心得开发流程6.16.26.36.46.5注意细节6.16.26.3 二、泛型编程1. 模板1.1 模板的概念1.2 …