封装可拖动弹窗(vue jquery引入到html的版本)

news2025/4/8 7:37:55

vue cli上简单的功能,在js上太难弄了,这个弹窗功能时常用到,保存起来备用吧
备注:deepseek这个人工智障写一堆有问题的我,还老服务器繁忙

效果图:

在这里插入图片描述

html代码:

<div class="modal-mask" v-show="qrcodeShow" @click.self="closeModal">
  <div class="modal-container" ref="modal" :style="modalStyle">
    <div
      class="modal-header"
      @mousedown="startDrag"
      @touchstart.prevent="startDrag"
      @mouseup="stopDrag"
      @touchend="stopDrag"
    >
      <span>获取app</span>
      <span class="close-btn" @click="closeModal">&times;</span>
    </div>
    <div class="image-container">
      <img :src="qrcodeImgUrl" class="modal-image" alt="弹窗图片" />
    </div>
  </div>
</div>

js代码:

data: {
	scanCodeList: [],
    qrcodeShow: false,
    qrcodeImgUrl: "**图片地址**",
    isDragging: false,
    startX: 0,
    startY: 0,
    translateX: 0,
    translateY: 0,
    modalRect: null,
},
  created() {
    this.$nextTick(() => {
      // 使用jQuery添加动画效果
      $(".modal-container").hide();
      // 监听弹窗状态变化
      this.$watch("qrcodeShow", (newVal) => {
        if (newVal) {
          $(".modal-container").fadeIn(300);
        } else {
          $(".modal-container").fadeOut(300);
        }
      });
    });
  },
  computed: {
    modalStyle() {
      return {
        transform: `translate(${this.translateX}px, ${this.translateY}px)`,
      };
    },
  },
  methods: {
    showModal() {
      this.qrcodeShow = true;
    },
    closeModal() {
      this.qrcodeShow = false;
    },
    // 开始拖动
    startDrag(e) {
      this.isDragging = true;
      const clientX = e.touches ? e.touches[0].clientX : e.clientX;
      const clientY = e.touches ? e.touches[0].clientY : e.clientY;

      // 记录初始位置
      this.startX = clientX - this.translateX;
      this.startY = clientY - this.translateY;

      // 获取弹窗尺寸
      this.modalRect = this.$refs.modal.getBoundingClientRect();

      // 添加事件监听
      document.addEventListener("mousemove", this.onDrag);
      document.addEventListener("touchmove", this.onDrag, { passive: false });
      document.addEventListener("mouseup", this.stopDrag);
      document.addEventListener("touchend", this.stopDrag);

      // 优化拖动体验
      document.body.style.cursor = "grabbing";
      document.body.style.userSelect = "none";
    },

    // 拖动处理
    onDrag(e) {
      if (!this.isDragging) return;

      // 获取坐标
      const clientX = e.touches ? e.touches[0].clientX : e.clientX;
      const clientY = e.touches ? e.touches[0].clientY : e.clientY;

      // 计算新位置
      let newX = clientX - this.startX;
      let newY = clientY - this.startY;

      // 计算边界
      const viewportWidth = document.documentElement.clientWidth;
      const viewportHeight = document.documentElement.clientHeight;
      const modalWidth = this.modalRect.width;
      const modalHeight = this.modalRect.height;

      // 有效边界
      const minX = -(viewportWidth - modalWidth) / 2;
      const minY = -(viewportHeight - modalHeight) / 2;
      const maxX = (viewportWidth - modalWidth) / 2;
      const maxY = (viewportHeight - modalHeight) / 2;

      // 应用约束
      newX = Math.max(minX, Math.min(newX, maxX));
      newY = Math.max(minY, Math.min(newY, maxY));

      // 更新位置
      this.translateX = newX;
      this.translateY = newY;
    },

    // 停止拖动
    stopDrag() {
      this.isDragging = false;

      // 移除事件监听
      document.removeEventListener("mousemove", this.onDrag);
      document.removeEventListener("touchmove", this.onDrag);
      document.removeEventListener("mouseup", this.stopDrag);
      document.removeEventListener("touchend", this.stopDrag);

      // 恢复样式
      document.body.style.cursor = "";
      document.body.style.userSelect = "";
    },

    // 重置位置到屏幕中央
    resetPosition() {
      this.$nextTick(() => {
        const modal = this.$refs.modal;
        if (modal) {
          const rect = modal.getBoundingClientRect();
          const viewportWidth = document.documentElement.clientWidth;
          const viewportHeight = document.documentElement.clientHeight;

          this.translateX = (viewportWidth - rect.width) / 2;
          this.translateY = (viewportHeight - rect.height) / 2;
        }
      });
    },
  },

css代码:

/* 遮罩层样式 */
  .modal-mask {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    z-index: 9998;
    display: flex;
    justify-content: center;
    align-items: center;

    /* 弹窗容器 */
    .modal-container {
      display: none;
      background: white;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
      width: 500px;
      height: 500px;
      z-index: 9999;
      position: relative;

      /* 弹窗头部 */
      .modal-header {
        height: 50px;
        padding: 15px;
        border-bottom: 1px solid #eee;
        display: flex;
        justify-content: space-between;
        align-items: center;
        cursor: move;
        user-select: none; /* 防止文字被选中 */
        span {
          font-size: 18px;
          font-weight: bold;
        }
        /* 关闭按钮样式 */
        .close-btn {
          cursor: pointer;
          font-size: 20px;
          color: #666;
          padding: 0 5px;
        }
      }

      /* 图片容器 */
      .image-container {
        padding: 20px;
        width: 100%;
        height: calc(100% - 50px);
        overflow: auto;
        img {
          width: 100%;
          height: 100%;
          object-fit: cover;
        }
      }
    }
  }

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

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

相关文章

【技术报告】GPT-4o 原生图像生成的应用与分析

【技术报告】GPT-4o 原生图像生成的应用与分析 1. GPT-4o 原生图像生成简介1.1 文本渲染能力1.2 多轮对话迭代1.3 指令遵循能力1.4 上下文学习能力1.5 跨模态知识调用1.6 逼真画质与多元风格1.7 局限性与安全性 2. GPT-4o 技术报告2.1 引言2.2 安全挑战、评估与缓解措施2.2.1 安…

初阶数据结构(3)顺序表

Hello~,欢迎大家来到我的博客进行学习&#xff01; 目录 1.线性表2.顺序表2.1 概念与结构2.2 分类2.2.1 静态顺序表2.2.2 动态顺序表 2.3 动态顺序表的实现初始化尾插头插尾删头删查找指定位置之前插入数据删除指定位置的数据销毁 1.线性表 首先我们需要知道的是&#xff0c;…

谷歌发布网络安全AI新模型Sec-Gemini v1

谷歌近日宣布推出实验性AI模型Sec-Gemini v1&#xff0c;旨在通过人工智能技术革新网络安全防御体系。该模型由Sec-Gemini团队成员Elie Burzstein和Marianna Tishchenko共同研发&#xff0c;旨在帮助网络安全人员应对日益复杂的网络威胁。 攻防不对称的破局之道 Sec-Gemini团队…

Meta LLaMA 4:对抗 GPT-4o 与 Claude 的开源王牌

2025 年 4 月&#xff0c;Meta 正式发布了 LLaMA 4 系列的首批两款模型。 这两款模型模型分别是&#xff1a;LLaMA 4 Scout 与 LLaMA 4 Maverick&#xff0c;均采用了 专家混合架构&#xff08;Mixture-of-Experts, MoE&#xff09;。 据 Meta 表示&#xff0c;这是首次有 …

企业级 ClickHouse Docker 离线部署实践指南20250407

企业级 ClickHouse Docker 离线部署实践指南 引言 在数据分析与日志处理日益重要的今天&#xff0c;ClickHouse 凭借其高性能、列式存储架构&#xff0c;成为企业在大数据分析中的首选引擎之一。本文基于一位金融行业从业者在离线网络环境中部署 ClickHouse 的真实实践过程&a…

DeepSeek-MLA

MLA 结构 需要缓存 KV 向量共用的压缩隐特征K 向量多头共享的带位置编码的向量 为什么带有位置信息的 Q 向量来自于隐特征向量&#xff0c;而带有位置的 K 向量来自于 H 向量且共享呢&#xff1f; 最好的方法肯定是从H向量直接计算并且不共享&#xff0c;但是会大大增加显存使…

pyTorch-迁移学习-学习率衰减-四种天气图片多分类问题

目录 1.导包 2.加载数据、拼接训练、测试数据的文件夹路径 3.数据预处理 3.1 transforms.Compose数据转化 3.2分类存储的图片数据创建dataloader torchvision.datasets.ImageFolder torch.utils.data.DataLoader 4.加载预训练好的模型(迁移学习) 4.1固定、修改预训练…

vscode Colipot 编程助手

1、登录到colipot&#xff0c;以github账号&#xff0c;关联登录 点击【continue】按钮&#xff0c;继续。 点击【打开Visual Studio Code】&#xff0c;回到vscode中。 2、问一下11? 可以看出&#xff0c;很聪明&#xff0c;一下子就算出来了。 3、帮我们写一个文件&#xf…

1、window 下SDL 下载使用, 测试环境搭建

1. SDL3下载 官网&#xff1a; https://www.libsdl.org/ 点击SDL Releases 或者 SDL GItHub 进入github下载&#xff1a; 因为自己在windows下使用的mingw,所以下载mingw版的&#xff0c;也可以 下载源码自己编译。 2. 项目搭建 这里使用的时mingw vsocde cmake, 可以使…

OpenGL学习笔记(模型材质、光照贴图)

目录 光照与材质光照贴图漫反射贴图采样镜面光贴图 GitHub主页&#xff1a;https://github.com/sdpyy OpenGL学习仓库:https://github.com/sdpyy1/CppLearn/tree/main/OpenGLtree/main/OpenGL):https://github.com/sdpyy1/CppLearn/tree/main/OpenGL 光照与材质 在现实世界里&…

视频分析设备平台EasyCVR打造汽车门店经营场景安全:AI智慧安防技术全解析

一、方案背景 某电动车企业不停爆出维权新闻&#xff0c;支持和反对的声音此起彼伏&#xff0c;事情不断发酵、反转&#xff0c;每天都有新消息&#xff0c;令人目不暇接。车展、车店作为维权事件的高发场所&#xff0c;事后复盘和责任认定时&#xff0c;安防监控和视频监控平…

Hibernate里的对象不同状态和Session的核心方法

临时状态的测试 Student student new Student("张三", "男", 22, new Date()); 以上student就是一个Transient(临时状态),此时student并没有被session进行托管&#xff0c;即在session的缓存中还不存在student这个对象&#xff0c;当执行完save方法后&a…

模型嵌入式部署

背景 自从深度学习大规模应用以来&#xff0c;其中一个应用方向就是将深度学习视觉算法部署到嵌入式平台上&#xff0c;使用NPU推理。虽然已经做了很久的模型部署&#xff0c;但一直都是在公司默默耕耘&#xff0c;为了发展一下自己“边缘部署专家”这个个人品牌&#xff0c;打…

Redlinux(2025.3.29)

1、将你的虚拟机的网卡模式设置为nat模式&#xff0c;给虚拟机网卡配置三个主机位分别为100、200、168的ip地址。(以nmtui命令为例) 2、测试你的虚拟机是否能够ping通网关和dns&#xff0c;如果不能请修改网关和dns的地址。 首先打开虚拟网络编辑器查看NAT设置里的网关IP&…

uni-app项目运行在浏览器、微信开发者工具、mumu模拟器

一、安装HBuilder X 1、下载HBuilder X 官网网址&#xff1a;https://dcloud.io/hbuilderx.html 根据电脑系统下载对应的版本&#xff08;我的电脑是Windows 10&#xff09; 2.安装HBuilder X 直接将HBuilderX.4.61.2025040322-alpha.zip解压到自己想要存放的文件夹中 双击…

2025-04-07 NO.3 Quest3 MR 配置

文章目录 1 MR 介绍1.1 透视1.2 场景理解1.3 空间设置 2 配置 MR 环境2.1 场景配置2.2 MR 配置 3 运行测试 配置环境&#xff1a; Windows 11Unity 6000.0.42f1Meta SDK v74.0.2Quest3 1 MR 介绍 1.1 透视 ​ 透视&#xff08;Passthrough&#xff09;是将应用的背景从虚拟的…

抓wifi无线空口包之Macbook Pro抓包(一)

参考&#xff1a; 在MAC OS上进行Wi-Fi抓包和空中包分析_空口抓包和无线网卡抓包的区别-CSDN博客 WireShark中802.11帧的类型、子类型对照表_wireshark 怎么看disassociate帧和deauthenticate-CSDN博客 一、在macbook pro上&#xff0c;点击option 同时点击右上角wifi 功能&a…

单元测试原则之——不要模拟值对象 (1)

1. 什么是值对象(Value Objects)? 值对象是指那些不可变且仅通过其属性(数据)来定义的对象。它们通常没有复杂的逻辑或行为,主要用于存储和传递数据。例如: ● 字符串(String) ● 数字(Integer, Double) ● 日期(LocalDate, Instant) ● 自定义的简单数据类(如…

版本控制工具——SVN

目录 【版本控制系统】 【SVN概述】 【SVN基本使用】 【解决SVN拉取文件到本地后不显示绿色图标问题】 【版本控制系统】 版本控制系统&#xff08;version control system&#xff09;是一种用于管理文件变更的软件工具&#xff0c;主要用于记录文件的修改历史&#xff0c…

2022第十三届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(题解解析)

记录刷题的过程、感悟、题解。 希望能帮到&#xff0c;那些与我一同前行的&#xff0c;来自远方的朋友&#x1f609; 大纲&#xff1a; 1、九进制转十进制-&#xff08;解析&#xff09;-简单的进制转化问题&#x1f604; 2、顺子日期-&#xff08;解析&#xff09;-考察日期 3…