<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>
全局配置参考文档