Vue+Elementui 弹窗全局配置第二版 监听鼠标是否移除浏览器

复制代码
<template>
  <div></div>
</template>

<script>
  export default {
    name: 'dialogDrag',
    data() {
      return {
        originalWidth: null,
        originalHeight: null,
        lastMousemoveHandler: null,
        lastMouseupHandler: null,
        mousedown: false
      }
    },

    created() {

    },
    mounted() {
      this.$nextTick(() => {
        this.dialogDrag()
      })
    },
    beforeDestroy() {
      this.clearLastEvents()
    },

    methods: {
      // 清除事件监听
      clearLastEvents() {
        this.mousedown = false
        if (this.lastMousemoveHandler) {
          document.removeEventListener('mousemove', this.lastMousemoveHandler)
          this.lastMousemoveHandler = null
        }
        if (this.lastMouseupHandler) {
          document.body.removeEventListener('mouseup', this.lastMouseupHandler)
          document.removeEventListener('mouseup', this.lastMouseupHandler)
          this.lastMouseupHandler = null
        }
      },

      // 处理窗口大小
      handleDialogSize(dragDom) {
        if (this.originalWidth || this.originalHeight) {
          // 还原弹窗的宽度和高度
          dragDom.style.width = this.originalWidth
          dragDom.style.height = this.originalHeight
          this.originalWidth = null
          this.originalHeight = null
        } else {
          // 保存当前弹窗的宽度和高度
          this.originalWidth = dragDom.style.width
          this.originalHeight = dragDom.style.height
          // 设置弹窗宽度和高度为窗口的宽度和高度
          dragDom.style.width = '100vw'
          dragDom.style.height = window.innerHeight + 'px'
          dragDom.style.overflow = 'auto'
        }
      },

      dialogDrag() {
        // 获取弹窗DOM
        const dragDom = this.$el.getElementsByClassName('el-dialog')[0]
        if (!dragDom) return

        // 弹窗标题顶部DOM
        const dialogHeaderDom = this.$el.getElementsByClassName('el-dialog__header')[0]
        if (!dialogHeaderDom) return

        // 设置拖动样式
        dialogHeaderDom.style.cursor = 'move'
        dialogHeaderDom.style.userSelect = 'none'
// 初始化弹窗位置为居中
//         this.$nextTick(() => {
//           setTimeout(() => {
//             // 1. 获取弹窗宽度
//             const dialogWidth = dragDom.offsetWidth/2
//             console.log('弹窗宽度:', dialogWidth)
//
//             // 2. 获取浏览器窗口宽度
//             const windowWidth = document.documentElement.clientWidth/2
//             console.log('窗口宽度:', windowWidth)
//
//             // 3. 计算左边距:(窗口宽度 - 弹窗宽度) / 2
//             const left = windowWidth - dialogWidth
//             console.log('计算的左边距:', left)
//
//             // 设置弹窗位置
//             dragDom.style.left = `${left}px`
//             dragDom.style.top = '2vh'
//           }, 500)
//         })
        const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)

        dialogHeaderDom.onmousedown = (e) => {
          // 清除上一次的事件监听
          this.clearLastEvents()

          // 处理双击
          if (e.detail === 2) {
            this.handleDialogSize(dragDom)
            return
          }

          // 阻止默认事件和冒泡
          e.stopPropagation()
          e.preventDefault()

          this.mousedown = true

          // 获取鼠标按下时的位置
          const startLeft = e.clientX - dialogHeaderDom.offsetLeft
          const startTop = e.clientY - dialogHeaderDom.offsetTop

          // 获取当前窗口的位置
          let styL, styT

          if (sty.left.includes('%')) {
            styL = +document.body.clientWidth * (+sty.left.replace('%', '') / 100)
            styT = +document.body.clientHeight * (+sty.top.replace('%', '') / 100)
          } else {
            styL = +sty.left.replace('px', '')
            styT = +sty.top.replace('px', '')
          }

          // 鼠标移动事件处理
          const handleMouseMove = (e) => {
            if (!this.mousedown) return false

            // 计算新位置
            let l = e.clientX - startLeft + styL
            let t = e.clientY - startTop + styT

            // 获取可移动的边界
            const offsetParent = dragDom.offsetParent || document.body
            const maxL = offsetParent.clientWidth - dragDom.clientWidth
            const maxT = offsetParent.clientHeight - dragDom.clientHeight +
              (sty.height.toString().split('p') && Number(sty.height.toString().split('p')[0])/1.5)

            // 限制移动范围
            l = Math.min(Math.max(l, -dragDom.clientWidth), maxL)
            t = Math.min(Math.max(t, 0), maxT)

            // 更新位置
            dragDom.style.left = `${l}px`
            dragDom.style.top = `${t}px`

            // 检查鼠标是否在有效范围内
            if (e.clientY <= 0 || e.clientY >= window.innerHeight ||
              e.clientX <= 0 || e.clientX >= window.innerWidth) {
              this.clearLastEvents()
            }
          }

          // 鼠标释放事件处理
          const handleMouseUp = () => {
            this.clearLastEvents()
          }

          // 保存事件处理函数
          this.lastMousemoveHandler = handleMouseMove
          this.lastMouseupHandler = handleMouseUp

          // 添加事件监听
          document.addEventListener('mousemove', handleMouseMove)
          document.addEventListener('mouseup', handleMouseUp)
          document.body.addEventListener('mouseup', handleMouseUp)

          // 添加鼠标离开窗口的监听
          document.addEventListener('mouseleave', (e) => {
            if (this.mousedown) {
              if (e.clientY <= 0 || e.clientY >= window.innerHeight ||
                e.clientX <= 0 || e.clientX >= window.innerWidth) {
                this.clearLastEvents()
              }
            }
          })
        }
      }
    }
  }
</script>

<style scoped>

</style>

全局配置参考文档

Vue2+ElementUI 弹窗全局拖拽 支持放大缩小_element plus 缩小弹窗-CSDN博客

相关推荐
林焱_RPAAI3 小时前
影刀RPA技术深度:CSS选择器高级实战指南——伪类属性选择器与性能对比完全解析
vue.js·react.js
陳陈陳5 小时前
🚀 前端流式输出革命:SSE + BFF 架构从零到一实战指南
vue.js·架构·node.js
黄泉路醉s9 小时前
在Vant+Vue+TypeScript的H移动前端使用UnoCSS
前端·vue.js·typescript
我要两颗404西柚11 小时前
Stage three:VUE工程化与实战工具
前端·javascript·vue.js
看昭奚恤哭13 小时前
基于 RuoYi-Vue-Pro 定制了一个后台管理系统 magic-admin , 开源出来!
前端·vue.js·开源
妙码生花1 天前
从 PHP 到 AI + Golang,程序员自救转型手记(四十五):前端远程下拉输入组件
前端·javascript·vue.js
Listen·Rain1 天前
AGENTS.md — Vue 3 Frontend Development
前端·javascript·vue.js
南风知我意啊1 天前
Vue3图片缩放拖拽组件全攻略
前端·javascript·vue.js
万亿少女的梦1681 天前
基于Spring Boot、Vue.js与MySQL的流浪猫狗救助系统设计与实现
vue.js·spring boot·mysql·javaweb·权限管理
早睡早起身体好1231 天前
Vue 3 路由与懒加载入门:从零完成一个迷你学习中心
javascript·vue.js·学习