Vue2+TS封装一个可全局拖拽的弹窗组件

news2024/10/2 2:01:19

Vue2+TS封装一个可全局拖拽的弹窗组件

ant组件的弹窗组件不支持拖拽,就很难受
项目里刚好有这个需求,就自己封装了一个

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

vue部分:

<template>
  <div class="image-standard-modal"
       :style="{ top: top + 'px', left: left + 'px' }"
       v-show="visible"
       v-on:mouseenter="onMouseEnter(true)"
       v-on:mouseleave="onMouseLeave">
    <div v-on:mouseenter="onMouseEnter(true)">
      <div class="header"
           v-on:mouseenter="onMouseEnter(true)">
        <span class="title">{{ title }}</span>
        <a-icon class="float-right"
                style="font-size: 18px;"
                type="close" />
        <a-divider />
      </div>
      <div class="body"
           v-on:mouseenter="onMouseEnter(false)">
        <slot></slot>
      </div>
    </div>
  </div>
</template>

script部分:

<script lang="ts">
import {
  Vue, Component, Prop, Emit,
} from 'vue-property-decorator';
import GBackstageBreadcrumb from '@/components/common/GBackstageBreadcrumb.vue';

@Component({
  name: 'DragAndDropModal',
  components: { BackstageBreadcrumb: GBackstageBreadcrumb },
})
export default class DragAndDropModal extends Vue {
  @Prop({ default: true }) visible!: boolean;

  @Prop({ default: '影像标准信息' }) title!: string;

  top = 200; // 弹窗的垂直位置

  left: any = '50%'; // 弹窗的水平位置

  dragging = false; // 是否正在拖拽

  diffX = 0; // 鼠标在弹窗内的水平偏移量

  diffY = 0; // 鼠标在弹窗内的垂直偏移量

  // 鼠标进入弹窗区域
  handleMouseDown(event) {
    event.preventDefault();
    this.dragging = true;
    this.diffX = event.clientX - event.target.getBoundingClientRect().left;
    this.diffY = event.clientY - event.target.getBoundingClientRect().top;
  }

  // 鼠标移动事件
  handleMouseMove(event) {
    if (this.dragging) {
      this.left = event.clientX - this.diffX;
      this.top = event.clientY - this.diffY;
    }
  }

  // 鼠标松开事件
  handleMouseUp() {
    this.dragging = false;
  }

  // 鼠标进入弹窗区域注册监听鼠标
  onMouseEnter(type) {
    console.log(type);
    if (type) {
      document.addEventListener('mousedown', this.handleMouseDown);
      document.addEventListener('mousemove', this.handleMouseMove);
      document.addEventListener('mouseup', this.handleMouseUp);
    } else {
      // 鼠标离开弹窗区域取消监听鼠标
      this.onMouseLeave();
    }
  }

  // 鼠标离开弹窗区域取消监听鼠标
  onMouseLeave() {
    if (this.dragging) {
      return;
    }
    document.removeEventListener('mousedown', this.handleMouseDown);
    document.removeEventListener('mousemove', this.handleMouseMove);
    document.removeEventListener('mouseup', this.handleMouseUp);
  }
}
</script>

style部分:

<style scoped lang='less'>
// 分割线
.ant-divider-horizontal {
  margin: 24px 0 0 0 !important;
}
.image-standard-modal{
  position: fixed; // 定位到最外层
  top: 100;
  left: 100;
  min-width: 400px;
  z-index: 1000;
  padding: 98px 24px 24px 24px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  border-radius: 4px;
  background-color: rgba(255, 255, 255, 0.8);
  .header {
    position: absolute;
    top: 0;
    left: 0;
    padding: 24px 24px 0 24px;
    background-color: white;
    width: 100%;
    .title {
      font-size: 16px;
      font-weight: 600;
      color: #333;
    }
  }
  .body{
    min-height: 200px;
    max-height: 70vh;
  }
}
</style>

完整代码:

<template>
  <div class="image-standard-modal"
       :style="{ top: top + 'px', left: left + 'px' }"
       v-show="visible"
       v-on:mouseenter="onMouseEnter(true)"
       v-on:mouseleave="onMouseLeave">
    <div v-on:mouseenter="onMouseEnter(true)">
      <div class="header"
           v-on:mouseenter="onMouseEnter(true)">
        <span class="title">{{ title }}</span>
        <a-icon class="float-right"
                style="font-size: 18px;"
                type="close" />
        <a-divider />
      </div>
      <div class="body"
           v-on:mouseenter="onMouseEnter(false)">
        <slot></slot>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import {
  Vue, Component, Prop, Emit,
} from 'vue-property-decorator';
import GBackstageBreadcrumb from '@/components/common/GBackstageBreadcrumb.vue';

@Component({
  name: 'DragAndDropModal',
  components: { BackstageBreadcrumb: GBackstageBreadcrumb },
})
export default class DragAndDropModal extends Vue {
  @Prop({ default: true }) visible!: boolean;

  @Prop({ default: '影像标准信息' }) title!: string;

  top = 200; // 弹窗的垂直位置

  left: any = '50%'; // 弹窗的水平位置

  dragging = false; // 是否正在拖拽

  diffX = 0; // 鼠标在弹窗内的水平偏移量

  diffY = 0; // 鼠标在弹窗内的垂直偏移量

  // 鼠标进入弹窗区域
  handleMouseDown(event) {
    event.preventDefault();
    this.dragging = true;
    this.diffX = event.clientX - event.target.getBoundingClientRect().left;
    this.diffY = event.clientY - event.target.getBoundingClientRect().top;
  }

  // 鼠标移动事件
  handleMouseMove(event) {
    if (this.dragging) {
      this.left = event.clientX - this.diffX;
      this.top = event.clientY - this.diffY;
    }
  }

  // 鼠标松开事件
  handleMouseUp() {
    this.dragging = false;
  }

  // 鼠标进入弹窗区域注册监听鼠标
  onMouseEnter(type) {
    console.log(type);
    if (type) {
      document.addEventListener('mousedown', this.handleMouseDown);
      document.addEventListener('mousemove', this.handleMouseMove);
      document.addEventListener('mouseup', this.handleMouseUp);
    } else {
      // 鼠标离开弹窗区域取消监听鼠标
      this.onMouseLeave();
    }
  }

  // 鼠标离开弹窗区域取消监听鼠标
  onMouseLeave() {
    if (this.dragging) {
      return;
    }
    document.removeEventListener('mousedown', this.handleMouseDown);
    document.removeEventListener('mousemove', this.handleMouseMove);
    document.removeEventListener('mouseup', this.handleMouseUp);
  }
}
</script>

<style scoped lang='less'>
// 分割线
.ant-divider-horizontal {
  margin: 24px 0 0 0 !important;
}

.image-standard-modal {
  position: fixed; // 定位到最外层
  top: 100;
  left: 100;
  min-width: 400px;
  z-index: 1000;
  padding: 98px 24px 24px 24px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  border-radius: 4px;
  background-color: rgba(255, 255, 255, 0.8);

  .header {
    position: absolute;
    top: 0;
    left: 0;
    padding: 24px 24px 0 24px;
    background-color: white;
    width: 100%;

    .title {
      font-size: 16px;
      font-weight: 600;
      color: #333;
    }
  }

  .body {
    min-height: 150px;
    max-height: 70vh;
  }
}
</style>


在其他组件使用:

    // 引入
    import DragAndDropModal from '@/map/DragAndDropModal.vue';
    
    // 注册
    @Component({
  	  name: 'OpenLayerMapRightLayout',
 	  components: {
        DragAndDropModal,
     },
   })
 	// 使用
    <DragAndDropModal>可拖拽弹窗</DragAndDropModal>

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

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

相关文章

Unity面试题:热更新篇

请简要介绍Unity热更新的原理和实现方式。 答&#xff1a;Unity热更新的原理是通过将游戏的资源和代码分离&#xff0c;将代码部分放置在服务器端&#xff0c;游戏启动时通过网络下载更新的代码并动态加载&#xff0c;以达到实现热更新的目的。实现方式包括AssetBundle、ILRunt…

【ArcGIS Pro二次开发】(57):地图系列

在ArcGIS Pro中&#xff0c;有一个地图系列&#xff0c;可以在一个布局中导出多个地图。 在SDK中为ArcGIS.Desktop.layout.MapSeries类和映射系列导出选项&#xff0c;可以以支持多页导出。 MapSeries类提供了一个静态CreateSpatialMapSeries方法&#xff0c;该方法使用指定的…

你是否好奇交流充电桩主板的安装维度?

你是否好奇交流充电桩主板的安装维度?安装环境、要求和方式&#xff0c;将影响充电桩的可靠性和安全性。 交流充电桩主板的安装环境至关重要&#xff0c;设备需要安装在室外&#xff0c;因此应选择防水、防火、耐候、耐腐蚀的材料。同时&#xff0c;安装要求具有良好的接地&am…

Redis入门-1

简介 nosql的一种&#xff0c;不是替代传统的sql&#xff0c;而是对传统的sql进行补充增强。redis用于短时间的高访问&#xff0c;其数据是存储在内存上的。 应用场景&#xff1a; 缓存 任务队列 消息队列 分布式锁 Linux系统上安装Redis 运行redis,进入/usr/local/redis-…

【LeetCode】对称二叉树 平衡二叉树

对称二叉树 即先判断根节点的左右子树相不相同&#xff0c;相同时&#xff0c;再判断左孩子的左子树和右孩子的右子树比较&#xff0c;左孩子的右子树和右孩子的左子树&#xff08;当两个都相同时才是对称的&#xff09;.....依次递推&#xff0c;过程中并设置一些不满足相同的…

虚拟机重启网络服务失败 Failed to start LSB:Bring up/down networking.

许久没有打开虚拟机了&#xff0c;今天一开打发现无法ping通网络 使用 ip addr 也获取不到ip信息 重启网络服务提示我 使用 systemctl status network.service 命令查看 出现以下报错 百度各种解决方案无效&#xff0c;才发现我为了加快电脑开机速度&#xff0c;把虚拟机的一些…

c++学习(智能指针)[29]

RALL RALL&#xff08;Resource Acquisition Is Initialization&#xff09;是一种 C 的编程技术&#xff0c;用于管理资源的获取和释放。它的基本思想是在对象的构造函数中获取资源&#xff0c;在对象的析构函数中释放资源&#xff0c;从而确保资源的正确获取和释放。 RALL 的…

实时数据监测与三维可视化:数字孪生技术引领工业互联网发展

随着工业互联网的快速发展&#xff0c;数字孪生技术作为其中的重要组成部分&#xff0c;正逐渐引起广泛关注。数字孪生是将实体世界的实时数据与数字模型相结合&#xff0c;形成实体与数字世界的虚拟镜像&#xff0c;为工业互联网带来了前所未有的效率和质量提升。 首先&#x…

【多模态】ALBEF-融合前对齐

目录 &#x1f341;&#x1f341;背景 &#x1f337;&#x1f337;网络结构 &#x1f385;&#x1f385;损失函数 &#x1f33c;&#x1f33c;动量蒸馏 &#x1f33a;&#x1f33a;下游任务结果 &#x1f4d2;&#x1f4d2;Grad-CAM 特征可视化 &#x1f6a6;&#x1f6a…

快速文件传输常见问题

我们所处的世界充斥着各种信息&#xff0c;能够迅速获得正确的数据往往是企业成功的关键因素。将文件从A点移动到B点需要考虑很多问题&#xff0c;但是当涉及需要在最短时间内送达全球各地收件人的大型关键任务文件时&#xff0c;就不能再使用Dropbox和 Google Drive 等方案了。…

flutter:二维码生成与读取

前言 这csdn真的是服了&#xff0c;图片里有个二维码就直接变成违规图片了。至于效果的话&#xff0c;自己运行一下看看吧。 生成 flutter中生成二维码可以使用 qr_flutter。 官方文档 https://pub-web.flutter-io.cn/packages/qr_flutter 安装 flutter pub add qr_flutt…

Dockerfile构建mysql

使用dockerfile构建mysql详细教学加案例 Dockerfile 文件 # 使用官方5.6版本&#xff0c;latest为默认版本 FROM mysql:5.6 #复制my.cof至容器内 ADD my.cnf /etc/mysql/my.cof #设置环境变量 密码 ENV MYSQL_ROOT_PASSWORD123456my.cof 文件 [mysqld] character-set-server…

【chrome扩展开发】vue-i18n使用问题及解决方案

记录chrome扩展开发时调用vue-i18n的一些问题和解决方法 环境 vue: ^3.3.4vue-i18n: ^9.2.2vite: ^4.4.8 错误1 Uncaught (in promise) EvalError: Refused to evaluate a string as JavaScript because unsafe-eval is not an allowed source of script in the following Con…

07 Ubuntu中使用poetry工具管理python环境——巨详细!!!

由于conda和ros2的环境实在太容易冲突了。我真的不敢再使用conda&#xff0c;着实是有些搞不明白这解释器之间的关系。 conda的卸载和ros2的安装暂不赘述&#xff0c;下面着重来说如何在Ubuntu中使用poetry进行包管理及遇到的问题。 1 安装poetry 由于在有写入权限的限制&am…

uniapp 返回上一页并刷新

如要刷新的是mine页面 在/pages/mine/improveInfo页面修改信息&#xff0c;点击保存后跳转到个人中心&#xff08;/pages/mine/index&#xff09;页面并刷新更新数据 点击保存按钮时执行以下代码&#xff1a; wx.switchTab({url: /pages/mine/index }) // 页面重载 let pages …

JConsole-的使用

文章目录 一、简介二、使用2.1 启动 JConsole2.2 连接到 Java 进程2.2.1 本地连接2.2.2 远程连接 2.3 监控 JVM 资源 一、简介 JConsole 是一种 Java 监控和管理控制台工具&#xff0c;可以用于监视 Java 虚拟机&#xff08;JVM&#xff09;的性能和资源利用情况。它提供了一种…

汉字姓名转拼音

import osimport pandas as pdfrom xpinyin import Pinyindownpath/Users/Kangyongqing/Downloads/ file1教师姓名转拼音.xlsxdtpd.read_excel(downpathfile1) print(dt.info()) dt[pinyin]dt[教师姓名].apply(lambda x:Pinyin().get_pinyin(x).split(-)[0].capitalize() .join…

antd select multiple模式 Dropdown onClick 失效

背景&#xff1a;当 Ant Design 的下拉菜单&#xff08;Dropdown&#xff09;在默认情况下从下方弹出&#xff0c;在某些情况下可能会因为页面空间不足而自动切换到上方弹出。这种位置变动可能导致点击事件无法触发。 复现描述&#xff1a;当输入搜索时&#xff0c;option会筛…

几乎与人类无异,机器人手通过触摸感知物体

原创 | 文 BFT机器人 人类即使在看不清物体的情况下也能够毫不费力的感知抓取物体&#xff0c;受到这一启发&#xff0c;加州大学圣迭戈分校工程师领导的研究小组开发出了一种新方法&#xff0c;使机械手能够不依赖视觉&#xff0c;仅通过触摸就能感知旋转物体。 利用他们的技…

什么是OCR?OCR技术详解

光学字符识别(Optical Character Recognition)简称为“OCR”。ORC是指对包含文本资料的图像文件进行分析识别处理&#xff0c;获取文字及版面信息的技术。 一般包括以下几个过程&#xff1a; 1.图像输入 针对不同格式的图像&#xff0c;有着不同的存储格式和压缩方式。目前&…