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

小秦哥  论坛元老 | 2025-4-3 15:00:37 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1625|帖子 1625|积分 4875

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


html代码:

  1. <div class="modal-mask" v-show="qrcodeShow" @click.self="closeModal">
  2.   <div class="modal-container" ref="modal" :style="modalStyle">
  3.     <div
  4.       class="modal-header"
  5.       @mousedown="startDrag"
  6.       @touchstart.prevent="startDrag"
  7.       @mouseup="stopDrag"
  8.       @touchend="stopDrag"
  9.     >
  10.       <span>获取app</span>
  11.       <span class="close-btn" @click="closeModal">&times;</span>
  12.     </div>
  13.     <div class="image-container">
  14.       <img :src="qrcodeImgUrl" class="modal-image" alt="弹窗图片" />
  15.     </div>
  16.   </div>
  17. </div>
复制代码
js代码:
  1. data: {
  2.         scanCodeList: [],
  3.     qrcodeShow: false,
  4.     qrcodeImgUrl: "**图片地址**",
  5.     isDragging: false,
  6.     startX: 0,
  7.     startY: 0,
  8.     translateX: 0,
  9.     translateY: 0,
  10.     modalRect: null,
  11. },
  12.   created() {
  13.     this.$nextTick(() => {
  14.       // 使用jQuery添加动画效果
  15.       $(".modal-container").hide();
  16.       // 监听弹窗状态变化
  17.       this.$watch("qrcodeShow", (newVal) => {
  18.         if (newVal) {
  19.           $(".modal-container").fadeIn(300);
  20.         } else {
  21.           $(".modal-container").fadeOut(300);
  22.         }
  23.       });
  24.     });
  25.   },
  26.   computed: {
  27.     modalStyle() {
  28.       return {
  29.         transform: `translate(${this.translateX}px, ${this.translateY}px)`,
  30.       };
  31.     },
  32.   },
  33.   methods: {
  34.     showModal() {
  35.       this.qrcodeShow = true;
  36.     },
  37.     closeModal() {
  38.       this.qrcodeShow = false;
  39.     },
  40.     // 开始拖动
  41.     startDrag(e) {
  42.       this.isDragging = true;
  43.       const clientX = e.touches ? e.touches[0].clientX : e.clientX;
  44.       const clientY = e.touches ? e.touches[0].clientY : e.clientY;
  45.       // 记录初始位置
  46.       this.startX = clientX - this.translateX;
  47.       this.startY = clientY - this.translateY;
  48.       // 获取弹窗尺寸
  49.       this.modalRect = this.$refs.modal.getBoundingClientRect();
  50.       // 添加事件监听
  51.       document.addEventListener("mousemove", this.onDrag);
  52.       document.addEventListener("touchmove", this.onDrag, { passive: false });
  53.       document.addEventListener("mouseup", this.stopDrag);
  54.       document.addEventListener("touchend", this.stopDrag);
  55.       // 优化拖动体验
  56.       document.body.style.cursor = "grabbing";
  57.       document.body.style.userSelect = "none";
  58.     },
  59.     // 拖动处理
  60.     onDrag(e) {
  61.       if (!this.isDragging) return;
  62.       // 获取坐标
  63.       const clientX = e.touches ? e.touches[0].clientX : e.clientX;
  64.       const clientY = e.touches ? e.touches[0].clientY : e.clientY;
  65.       // 计算新位置
  66.       let newX = clientX - this.startX;
  67.       let newY = clientY - this.startY;
  68.       // 计算边界
  69.       const viewportWidth = document.documentElement.clientWidth;
  70.       const viewportHeight = document.documentElement.clientHeight;
  71.       const modalWidth = this.modalRect.width;
  72.       const modalHeight = this.modalRect.height;
  73.       // 有效边界
  74.       const minX = -(viewportWidth - modalWidth) / 2;
  75.       const minY = -(viewportHeight - modalHeight) / 2;
  76.       const maxX = (viewportWidth - modalWidth) / 2;
  77.       const maxY = (viewportHeight - modalHeight) / 2;
  78.       // 应用约束
  79.       newX = Math.max(minX, Math.min(newX, maxX));
  80.       newY = Math.max(minY, Math.min(newY, maxY));
  81.       // 更新位置
  82.       this.translateX = newX;
  83.       this.translateY = newY;
  84.     },
  85.     // 停止拖动
  86.     stopDrag() {
  87.       this.isDragging = false;
  88.       // 移除事件监听
  89.       document.removeEventListener("mousemove", this.onDrag);
  90.       document.removeEventListener("touchmove", this.onDrag);
  91.       document.removeEventListener("mouseup", this.stopDrag);
  92.       document.removeEventListener("touchend", this.stopDrag);
  93.       // 恢复样式
  94.       document.body.style.cursor = "";
  95.       document.body.style.userSelect = "";
  96.     },
  97.     // 重置位置到屏幕中央
  98.     resetPosition() {
  99.       this.$nextTick(() => {
  100.         const modal = this.$refs.modal;
  101.         if (modal) {
  102.           const rect = modal.getBoundingClientRect();
  103.           const viewportWidth = document.documentElement.clientWidth;
  104.           const viewportHeight = document.documentElement.clientHeight;
  105.           this.translateX = (viewportWidth - rect.width) / 2;
  106.           this.translateY = (viewportHeight - rect.height) / 2;
  107.         }
  108.       });
  109.     },
  110.   },
复制代码
css代码:

  1. /* 遮罩层样式 */
  2.   .modal-mask {
  3.     position: fixed;
  4.     top: 0;
  5.     left: 0;
  6.     width: 100%;
  7.     height: 100%;
  8.     background: rgba(0, 0, 0, 0.5);
  9.     z-index: 9998;
  10.     display: flex;
  11.     justify-content: center;
  12.     align-items: center;
  13.     /* 弹窗容器 */
  14.     .modal-container {
  15.       display: none;
  16.       background: white;
  17.       border-radius: 8px;
  18.       box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
  19.       width: 500px;
  20.       height: 500px;
  21.       z-index: 9999;
  22.       position: relative;
  23.       /* 弹窗头部 */
  24.       .modal-header {
  25.         height: 50px;
  26.         padding: 15px;
  27.         border-bottom: 1px solid #eee;
  28.         display: flex;
  29.         justify-content: space-between;
  30.         align-items: center;
  31.         cursor: move;
  32.         user-select: none; /* 防止文字被选中 */
  33.         span {
  34.           font-size: 18px;
  35.           font-weight: bold;
  36.         }
  37.         /* 关闭按钮样式 */
  38.         .close-btn {
  39.           cursor: pointer;
  40.           font-size: 20px;
  41.           color: #666;
  42.           padding: 0 5px;
  43.         }
  44.       }
  45.       /* 图片容器 */
  46.       .image-container {
  47.         padding: 20px;
  48.         width: 100%;
  49.         height: calc(100% - 50px);
  50.         overflow: auto;
  51.         img {
  52.           width: 100%;
  53.           height: 100%;
  54.           object-fit: cover;
  55.         }
  56.       }
  57.     }
  58.   }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小秦哥

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表