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

相关推荐
卤蛋fg627 分钟前
vxe-table 列拖拽排序与行拖拽排序:让表格布局任意排序
vue.js
粉末的沉淀1 小时前
vue:Vite项目中高效管理纯色SVG图标的方案
前端·javascript·vue.js
卤蛋fg61 小时前
vxe-table 列宽与行高拖拽调整:让表格布局极其灵活,拖拽功能非常强大
vue.js
向日的葵0062 小时前
Vue 路由传参的三种方式(三)
vue.js·路由
如果超人不会飞2 小时前
TinyVue Checkbox复选框组件使用指南
前端·vue.js
如果超人不会飞2 小时前
TinyVue Radio单选框组件使用指南
vue.js
鲁班小子2 小时前
Vite resolve.dedupe 使用教程
vue.js·vite
如果超人不会飞2 小时前
TinyVue Input输入框组件使用指南
vue.js
如果超人不会飞2 小时前
TinyVue Pager分页组件使用指南
前端·vue.js
大刚测试开发实战3 小时前
TestHub重磅更新!AI用例生成增加流式输出、Markdown文档上传、模型配置检测、AI评审开关控制...
vue.js·后端·github