前端使用Vue和Element实现可拖动弹框效果,且不影响底层元素操作(可拖拽的视频实时播放弹框,底层元素可以正常操作)

news2024/11/15 17:41:06

简述:在前端开发中,弹框和实时视频播放是常见的需求。这里来简单记录一下,如何使用Vue.js和Element UI实现一个可拖动的弹框,并在其中播放实时视频。同时,确保在拖拽弹框时,底层元素仍然可以操作。


一、项目初始化,以Vue项目为例

首先,确保你的项目已经安装了Element UI。如果没有安装,可以使用以下命令进行安装并注册:

npm install element-ui

// 或者

cnpm install element-ui


二、创建Vue组件

这里我们创建一个包含实时视频播放功能的弹框组件。这个组件将使用Element UI的el-dialog组件,并添加拖动功能,同时添加CSS代码。确保在拖拽时底层元素可以操作。

1. 弹框组件

<template>
  <!-- 弹出框 -->
  <el-dialog
    title="实时视频播放"
    :visible.sync="dialogVisible"
    width="30%"
    :before-close="handleClose"
    :modal="false"
    :close-on-click-modal="false"
    class="cesium_dialog"
  >
    <flvVue :Url="rtsp1" v-if="dialogVisible"></flvVue>
    <span slot="footer" class="dialog-footer"> </span>
  </el-dialog>
</template>

<script>

export default {

  data() {
    return {
      dialogVisible: false, // 弹框显示状态
      rtsp1: 'rtsp://your-stream-url' // 实时视频流地址
    };
  },

  methods: {
    // 打开弹框事件
    DialogOpen(RtspUrl) {
      this.dialogVisible = true; // 显示弹框
    },
    // 关闭弹框事件
    handleClose() {
      this.dialogVisible = false; // 关闭弹框
    }
  },

};};
</script>

<style>
/* 在你的 CSS 文件或 <style> 标签中添加 */
::v-deep .el-dialog__wrapper {
  pointer-events: none !important; /* 禁用遮罩层的点击事件 */
}
::v-deep .el-dialog__wrapper .el-dialog {
  pointer-events: auto !important; /* 允许对话框内的元素交互 */
  margin-top: 20vh !important; /* 设置弹框距顶部的距离 */
}
</style>

2. 拖拽功能的实现

创建一个draggable.js文件,用于实现弹框的拖拽功能:

// src/mixins/draggable.js
export default {
  mounted() {
    // 获取对话框的头部元素
    const dialogHeaderEl = this.$el.querySelector('.el-dialog__header');
    // 获取整个对话框元素
    const dragDom = this.$el.querySelector('.el-dialog');
    // 设置头部的光标为移动样式,表示可以拖动
    dialogHeaderEl.style.cursor = 'move';

    // 函数用于获取元素的计算样式
    const getStyle = (function () {
      if (window.document.currentStyle) {
        // 对于旧版 IE,使用 currentStyle
        return (dom, attr) => dom.currentStyle[attr];
      } else {
        // 对于现代浏览器,使用 getComputedStyle
        return (dom, attr) => getComputedStyle(dom, false)[attr];
      }
    })();

    // 鼠标按下事件处理程序
    dialogHeaderEl.onmousedown = (e) => {
      // 计算鼠标点击点相对于对话框头部的偏移量
      const disX = e.clientX - dialogHeaderEl.offsetLeft;
      const disY = e.clientY - dialogHeaderEl.offsetTop;

      // 获取对话框的宽度和高度
      const dragDomWidth = dragDom.offsetWidth;
      const dragDomHeight = dragDom.offsetHeight;

      // 获取浏览器窗口的宽度和高度
      const screenWidth = document.body.clientWidth;
      const screenHeight = document.body.clientHeight;

      // 计算对话框拖动的边界
      const minDragDomLeft = dragDom.offsetLeft; // 左边界
      // 右边界
      const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth; 
      const minDragDomTop = dragDom.offsetTop; // 上边界
      // 下边界
      const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight; 

      // 获取对话框当前位置的样式(左和上),处理 px 或百分比单位
      let styL = getStyle(dragDom, 'left');
      let styT = getStyle(dragDom, 'top');

      // 处理百分比单位,将其转换为绝对像素值
      if (styL.includes('%')) {
        styL = +document.body.clientWidth * (+styL.replace(/%/g, '') / 100);
        styT = +document.body.clientHeight * (+styT.replace(/%/g, '') / 100);
      } else {
        // 处理 px 单位
        styL = +styL.replace(/px/g, '');
        styT = +styT.replace(/px/g, '');
      }

      // 鼠标移动事件处理程序
      document.onmousemove = function (e) {
        // 计算新的位置
        let left = e.clientX - disX;
        let top = e.clientY - disY;

        // 边界处理:防止对话框拖动超出边界
        if (-left > minDragDomLeft) {
          left = -minDragDomLeft;
        } else if (left > maxDragDomLeft) {
          left = maxDragDomLeft;
        }

        if (-top > minDragDomTop) {
          top = -minDragDomTop;
        } else if (top > maxDragDomTop) {
          top = maxDragDomTop;
        }

        // 更新对话框的位置
        dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
      };

      // 鼠标释放事件处理程序
      document.onmouseup = function () {
        // 解除鼠标移动和释放事件的绑定
        document.onmousemove = null;
        document.onmouseup = null;
      };

    };
  }
};};

3. 整合拖拽功能

draggable.js文件混入到你的Vue组件中,使得弹框可以实现拖动功能,同时确保拖拽时底层元素仍然可以操作。

import draggable from "@/utils/hs/draggable.js"; // 引入拖拽功能

export default {

  // 混入拖拽功能
  mixins: [draggable],

  data() {
    return {
      ......
    };
  },
  methods: {
      ......
  },

};};


三. 完整代码

1. Vue

<template>
  <!-- 弹出框 -->
  <el-dialog
    title="实时视频播放"
    :visible.sync="dialogVisible"
    width="30%"
    :before-close="handleClose"
    :modal="false"
    :close-on-click-modal="false"
    class="cesium_dialog"
  >
    <flvVue :Url="rtsp1" v-if="dialogVisible"></flvVue>
    <span slot="footer" class="dialog-footer"> </span>
  </el-dialog>
</template>

<script>
import draggable from "@/utils/hs/draggable.js"; // 引入拖拽功能

export default {

  // 混入拖拽功能
  mixins: [draggable],

  data() {
    return {
      dialogVisible: false,
      rtsp1: 'rtsp://your-stream-url'
    };
  },

  methods: {
    DialogOpen(RtspUrl) {
      this.dialogVisible = true;
    },
    handleClose() {
      this.dialogVisible = false;
    }
  },

};};
</script>

<style>
/* 在你的 CSS 文件或 <style> 标签中添加 */
::v-deep .el-dialog__wrapper {
  pointer-events: none !important; /* 禁用遮罩层的点击事件 */
}
::v-deep .el-dialog__wrapper .el-dialog {
  pointer-events: auto !important; /* 允许对话框内的元素交互 */
  margin-top: 20vh !important; /* 设置弹框距顶部的距离 */
}
</style>

2. JS

// src/mixins/draggable.js

export default {
  mounted() {
    // 获取对话框的头部元素
    const dialogHeaderEl = this.$el.querySelector('.el-dialog__header');
    // 获取整个对话框元素
    const dragDom = this.$el.querySelector('.el-dialog');
    // 设置头部的光标为移动样式,表示可以拖动
    dialogHeaderEl.style.cursor = 'move';

    // 函数用于获取元素的计算样式
    const getStyle = (function () {
      if (window.document.currentStyle) {
        // 对于旧版 IE,使用 currentStyle
        return (dom, attr) => dom.currentStyle[attr];
      } else {
        // 对于现代浏览器,使用 getComputedStyle
        return (dom, attr) => getComputedStyle(dom, false)[attr];
      }
    })();

    // 鼠标按下事件处理程序
    dialogHeaderEl.onmousedown = (e) => {
      // 计算鼠标点击点相对于对话框头部的偏移量
      const disX = e.clientX - dialogHeaderEl.offsetLeft;
      const disY = e.clientY - dialogHeaderEl.offsetTop;

      // 获取对话框的宽度和高度
      const dragDomWidth = dragDom.offsetWidth;
      const dragDomHeight = dragDom.offsetHeight;

      // 获取浏览器窗口的宽度和高度
      const screenWidth = document.body.clientWidth;
      const screenHeight = document.body.clientHeight;

      // 计算对话框拖动的边界
      const minDragDomLeft = dragDom.offsetLeft; // 左边界
      // 右边界
      const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
      const minDragDomTop = dragDom.offsetTop; // 上边界
      // 下边界
      const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight; 
      // 获取对话框当前位置的样式(左和上),处理 px 或百分比单位
      let styL = getStyle(dragDom, 'left');
      let styT = getStyle(dragDom, 'top');

      // 处理百分比单位,将其转换为绝对像素值
      if (styL.includes('%')) {
        styL = +document.body.clientWidth * (+styL.replace(/%/g, '') / 100);
        styT = +document.body.clientHeight * (+styT.replace(/%/g, '') / 100);
      } else {
        // 处理 px 单位
        styL = +styL.replace(/px/g, '');
        styT = +styT.replace(/px/g, '');
      }

      // 鼠标移动事件处理程序
      document.onmousemove = function (e) {
        // 计算新的位置
        let left = e.clientX - disX;
        let top = e.clientY - disY;

        // 边界处理:防止对话框拖动超出边界
        if (-left > minDragDomLeft) {
          left = -minDragDomLeft;
        } else if (left > maxDragDomLeft) {
          left = maxDragDomLeft;
        }

        if (-top > minDragDomTop) {
          top = -minDragDomTop;
        } else if (top > maxDragDomTop) {
          top = maxDragDomTop;
        }

        // 更新对话框的位置
        dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
      };

      // 鼠标释放事件处理程序
      document.onmouseup = function () {
        // 解除鼠标移动和释放事件的绑定
        document.onmousemove = null;
        document.onmouseup = null;
      };
    };
  }
};};


四、小结

通过以上步骤,我们实现了一个可拖动的弹框,并在其中播放实时视频。我们使用了Vue.js和Element UI,并通过自定义混入实现了拖拽功能。同时,通过设置pointer-events属性,确保在拖拽弹框时底层元素仍然可以操作。

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

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

相关文章

用python生成词频云图(python实例二十一)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.词频云图 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&a…

B站启用adblock插件导致无法看到评论

1 进入adblock插件的设置页面 2 进入自定义规则页面&#xff0c;编辑过滤规则 删除掉这一项 www.bilibili.com##P 然后&#xff0c;点击保存&#xff1b; 刷新页面就可以看到B站评论区的评论了。

可以拖拽的富文本编辑器(VueDragResize,quill-editor)

该功能实现一个帮助文档的展示和编辑功能&#xff0c;默认进去只能查看帮助文档的内容&#xff0c;点击编辑可以进行富文本编辑器的编辑功能。 出现的问题1.如何隐藏富文本编辑的工具栏并且禁止编辑 //隐藏工具栏this.toolbar this.$refs.myTextEditor.quill.getModule(toolb…

化妆品3D虚拟三维数字化营销展示更加生动、真实、高效!

随着人们越来越追求高速便捷的生活工作方式&#xff0c;企业在营销市场也偏国际化&#xff0c;借助VR全景制作技术&#xff0c;将企业1:1复刻到云端数字化世界&#xff0c;能带来高沉浸式的逼真、震撼效果。 通过我们独特的漫游点自然场景过渡技术&#xff0c;您将置身于一个真…

开发个人Go-ChatGPT--5 模型管理 (一)

开发个人Go-ChatGPT–5 模型管理 (一) 背景 开发一个chatGPT的网站&#xff0c;后端服务如何实现与大模型的对话&#xff1f;是整个项目中开发困难较大的点。 如何实现上图的聊天对话功能&#xff1f;在开发后端的时候&#xff0c;如何实现stream的响应呢&#xff1f;本文就…

JRE、JVM、JDK分别是什么。

JDK JDK的英文全称是Java Development Kit。JDK是用于制作程序和Java应用程序的软件开发环境。JDK 是 Java 开发工具包&#xff0c;它是 Java 开发者用来编写、编译、调试和运行 Java 程序的集合。JDK 包括了 Java 编译器&#xff08;javac&#xff09;、Java 运行时环境&…

SLAM相关知识

目前在SLAM上的传感器主要分为两大类&#xff1a;激光雷达和摄像头 激光雷达&#xff1a;单线、多线 摄像头&#xff1a;单目相机&#xff08;普通USB相机&#xff09;、双目相机&#xff08;2个普通的USB相机&#xff09;、单目结构光&#xff08;深度相机&#xff09;、双目…

编辑器 goland 和 visual studio code

goland 编辑器做的真是太好了&#xff0c;面向 go 代码的定制设计&#xff0c;但它是收费软件&#xff0c;价格还贵的超出了自己的经济能力范围。有时候想打几行代码&#xff0c;却没有趁手的兵器&#xff0c;真是难受。但求助免费破解版吧&#xff0c;又需要关注公众号&#x…

用流式数据库解决「自动化检测服务器性能异常」难题

对 DevOps 团队来说&#xff0c;检测大量服务器的性能异常并尽快响应一直是个挑战。他们设置了各种指标来监控服务器性能&#xff0c;但诊断性能问题复杂且耗时&#xff0c;因为诊断数据的量可能非常大。越来越多的人认为这个过程应该自动化。但怎么做呢&#xff1f; 流式系统…

@Slf4j idea标红Cannot resolve symbol ‘log‘

一、背景 时间久了没有应用idea,打开工程后项目 log 提示报红&#xff0c;未能解析&#xff0c;Cannot resolve symbol log &#xff0c;Slf4j 注解正常&#xff0c;应用的lombok插件。 检查lombok插件安装情况&#xff0c;发现未安装&#xff0c;重新安装重启idea后正常。 二…

pdf容量大小怎么改,pdf容量太大怎么变小

在数字化时代&#xff0c;pdf文件因其稳定性和跨平台兼容性而成为工作、学习和生活中不可或缺的文件格式。然而&#xff0c;随着文件内容的丰富&#xff0c;pdf文件的体积也日益增大&#xff0c;给存储和传输带来了不少困扰。本文将为你详细介绍多种实用的pdf文件压缩方法&…

怎样在 PostgreSQL 中优化对 UUID 数据类型的索引和查询?

文章目录 一、UUID 数据类型概述二、UUID 索引和查询的性能问题三、优化方案&#xff08;一&#xff09;选择合适的索引类型&#xff08;二&#xff09;压缩 UUID&#xff08;三&#xff09;拆分 UUID&#xff08;四&#xff09;使用覆盖索引&#xff08;五&#xff09;优化查询…

AutoHotKey自动热键(五)添加WINDOWS秘笈指令-输入瞬间启动功能

在AUTOHOTKEY的使用中,不仅仅可以监听组合热键,还可以监听正常文本击键录入,这是另一种监听方式,比如依次击键jsq之后直接弹出<计算器>工具,或者依次击键sj之后直接输出135****5564的手机号码,等等,这就是autohotkey的录入击键监听,以双冒号为开头:: 因这种录入监听像极了…

Vue3使用ref绑定组件获取valueRef.value为null的解决

问题&#xff1a; onMounted(() > {nextTick(()>{console.log(treeselectRef, treeselectRef.value);console.log(treeselectRef.value, treeselectRef.value);}); });输出&#xff1a; 查看绑定和定义都没有问题&#xff0c;还是获取不到 解决&#xff1a;使用getCur…

transformer网络学习

Transformer encoder-decoder模型之间共享的是Encoder最后一层输出的hidden-state。 GitHub - huggingface/transformers: &#x1f917; Transformers: State-of-the-art Machine Learning for Pytorch, TensorFlow, and JAX. Bert2Bert中&#xff0c;Encoder的hidden-state同…

变阻器的分类

变阻器作为用于调节电路中电阻值的电子元件&#xff0c;在电子电路中具有广泛的应用。根据不同的工作原理和结构形式&#xff0c;变阻器可以分为多种类型。以下是对变阻器分类的详细阐述&#xff1a; 一、按工作原理分类 电位器是一种通过滑动端位置调节电阻值的变阻器&#x…

移动公厕有无人显示屏为何多采用RS485、IO信号通讯方式

在户外活动、临时集会或是应急情况下&#xff0c;移动公厕作为解决人们生理需求的重要设施&#xff0c;发挥着不可替代的作用。然而&#xff0c;随着人口密度的增加和对公共卫生要求的提高&#xff0c;如何确保移动公厕的高效利用和良好维护&#xff0c;成为了组织者和管理者面…

大模型2024的问题在哪里?

自从大模型吹响新一轮技术革命的号角后&#xff0c;整个行业各个层次都面临大模型带来的范式转换。我今年在 4 月份上海举办的全球机器学习技术大会上演讲时曾提出&#xff0c;大模型为计算产业带来了计算范式、开发范式、交互范式的三大范式改变。今天是软件研发技术大会&…

使用jdk11运行javafx程序和jdk11打包jre包含javafx模块

我们都知道jdk11是移除了javafx的,如果需要使用javafx,需要单独下载。 这就导致我们使用javafx开发的桌面程序使用jdk11时提示缺少javafx依赖。但这是可以通过下面的方法解决。 一,使用jdk11运行javafx程序 我们可以通过设置vmOptions来使用jdk11运行javafx程序 1,添加j…