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博客

相关推荐
无羡仙7 小时前
从零构建 Vue 弹窗组件
前端·vue.js
计算机毕设VX:Fegn089510 小时前
计算机毕业设计|基于springboot + vue动物园管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
北辰alk10 小时前
深入理解Vue数据流:单向与双向的哲学博弈
vue.js
北辰alk11 小时前
解决Vue打包后静态资源图片失效的终极指南
vue.js
Jing_Rainbow13 小时前
【Vue-2/Lesson62(2025-12-10)】模块化与 Node.js HTTP 服务器开发详解🧩
前端·vue.js·node.js
冴羽14 小时前
2026 年 Web 前端开发的 8 个趋势!
前端·javascript·vue.js
五仁火烧15 小时前
Vue3 项目的默认端口行为
服务器·vue.js·nginx·容器·vue
Younglina16 小时前
一个纯前端的网站集合管理工具
前端·vue.js·chrome
pas13616 小时前
31-mini-vue 更新element的children
前端·javascript·vue.js
jllws117 小时前
硬件_键盘是如何工作的(一)
计算机外设·硬件