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

相关推荐
蜡台18 分钟前
vue params传参刷新网页数据丢失解决方法
前端·javascript·vue.js
青柠代码录1 小时前
【Vite】vite.config.ts 配置详解(Vite 8)
vue.js
Ruihong2 小时前
你的 Vue 3 useAttrs(),VuReact 会编译成什么样的 React?
vue.js·react.js·面试
yusirxiaer2 小时前
为什么 markRaw 能修复 Vue 3 + ECharts 的 resize 报错
javascript·vue.js·echarts
赛博切图仔3 小时前
前端性能内卷终点?Signals 正在重塑我们的开发习惯
前端·javascript·vue.js
一 乐3 小时前
饮食营养信息|基于springboot + vue饮食营养管理信息平台系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·饮食营养管理信息系统
军军君013 小时前
数字孪生监控大屏实战模板:空气污染监控
前端·javascript·vue.js·typescript·前端框架·echarts·数字孪生
练习前端两年半4 小时前
Vue3 KeepAlive 深度揭秘:组件缓存的魔法是如何实现的?
前端·vue.js·面试
SuperEugene5 小时前
Vue3 配置驱动弹窗:JSON配置弹窗内容/按钮,避免重复开发弹窗|配置驱动开发实战篇
前端·javascript·vue.js·前端框架·json
小贵子的博客5 小时前
基于Vue3 和 Ant Design Vue实现Modal弹窗拖拽组件
前端·javascript·vue.js