一、实现原理
1、获取鼠标在div中的位置
2、设置 div 的 left 和 top 使其跟随鼠标位置移动,达到拖拽的效果
二、实现步骤
1、UI
{{title}}
X
2、组件定义props
visible:控制弹窗显示,false 不显示,true 显示
title:弹窗标题,默认 提示
confirmtext:确认按钮文案,默认 确定
canceltext: 取消按钮文案,默认 取消
showCancelButton:是否显示取消按钮,false 否,true 是,默认 true
3、组件事件回调 $emit
methods: {
cancel: function () {
// .sync 实现弹窗显示 or 隐藏
this.$emit("update:visible", false)
this.$emit("cancel")
},
confirm: function () {
this.$emit("confirm")
},
},
4、组件使用到的相关属性
- event.clientX / event.clientY:鼠标触发时指针相对于浏览器可视区域的水平 / 垂直坐标
- vnode.offsetLeft / vnode.offsetTop属性:当前元素距离某个定位父辈元素左边 / 顶部的距离
- vnode.offsetWidth / vnode.offsetHeight:当前元素的宽 / 高度,包括边框和填充
- window.innerHeight / window.innerHeightWidth:获取当前页面可视区的宽高(包括滚动条)
5、组件自定义指令
https://cn.vuejs.org/v2/guide/custom-directive.html
6、组件使用到的相关事件
- onmousedown 鼠标按下事件
- onmousemove 鼠标移动事件
- onmouseup 鼠标松开事件
el.onmousedown = function(e){
console.log('鼠标已按下:', e)
}
el.onmousemove = function(e){
console.log('鼠标移动中:', e)
}
el.onmouseup = function(e){
console.log('鼠标已松开:', e)
}
// 注:el 表示当前触发的元素
7、实现思路
- 给弹窗绑定onmousedown事件,获取鼠标在弹窗中按下的位置(以弹窗左上角为原点)
el.onmousedown = ((event) => {
let mouseX = event.clientX - vnode.offsetLeft
let mouseY = event.clientY - vnode.offsetTop
})
- document绑定onmousemove事件,获取当前的鼠标位置,当前鼠标位置 - 鼠标在弹窗中的相对位置,通过style设置弹窗的当前位置
document.onmousemove = ((event) => {
let left, top
// 获取新的鼠标位置(event.clientX, event.clientY)
// 弹窗应该在的位置(left, top)
// (mouseX, mouseY) 鼠标按下时的坐标
left = event.clientX - mouseX
top = event.clientY - mouseY
// 赋值移动
vnode.style.left = left + 'px'
vnode.style.top = top + 'px'
})
- 鼠标松开解绑document的鼠标事件onmousedown,onmousemove
document.onmouseup = (() => {
document.onmousemove = document.onmouseup = null
})
- 控制弹窗只能在浏览器可视区内被拖拽,需要设置水平和垂直方向的最大最小移动位置,在“赋值移动”前添加下面代码
// 获取弹窗在页面中距X轴的最小、最大 位置
let minX = -vnode.offsetWidth / 2 + 100
let maxX = window.innerWidth + vnode.offsetWidth / 2 - 100
if (left <= minX) {
left = minX
} else if (left >= maxX) {
left = maxX
}
// 获取弹窗在页面中距Y轴的最小、最大 位置
let minY = vnode.offsetHeight / 2
let maxY = window.innerHeight + vnode.offsetHeight / 2 - 100
if (top <= minY) {
top = minY
} else if (top >= maxY) {
top = maxY
}
- 浏览器可视区大小变化时重置弹窗的位置到初始化状态
window.onresize = (() => {
vnode.style.left = "50%"
vnode.style.top = "50%"
})
- 控制鼠标按下弹窗指定区域才能拖拽弹窗,在 onmousedown 事件中添加下面代码
// my_dialog_title 指定区域对应元素的类名
if (event.target.className !== "my_dialog_title") {
return
}
8、完整拖拽指令
directives: {
drag: {
inserted: function (el, binding, vnode) {
vnode = vnode.elm
el.onmousedown = ((event) => {
if (event.target.className !== "my_dialog_title") {
return
}
// (clientX, clientY)点击位置距离当前可视区域的坐标(x,y)
// offsetLeft, offsetTop 距离上层或父级的左边距和上边距
// 获取鼠标在弹窗中的位置
let mouseX = event.clientX - vnode.offsetLeft
let mouseY = event.clientY - vnode.offsetTop
// 绑定移动和停止函数
document.onmousemove = ((event) => {
let left, top
// 获取新的鼠标位置(event.clientX, event.clientY)
// 弹窗应该在的位置(left, top)
left = event.clientX - mouseX
top = event.clientY - mouseY
// offsetWidth、offsetHeight 当前元素的宽度
// innerWidth、innerHeight 浏览器可视区的宽度和高度
// 获取弹窗在页面中距X轴的最小、最大 位置
let minX = -vnode.offsetWidth / 2 + 100
let maxX = window.innerWidth + vnode.offsetWidth / 2 - 100
if (left <= minX) {
left = minX
} else if (left >= maxX) {
left = maxX
}
// 获取弹窗在页面中距Y轴的最小、最大 位置
let minY = vnode.offsetHeight / 2
let maxY =window.innerHeight + vnode.offsetHeight / 2 - 100
if (top <= minY) {
top = minY
} else if (top >= maxY) {
top = maxY
}
// 赋值移动
vnode.style.left = left + 'px'
vnode.style.top = top + 'px'
})
document.onmouseup = (() => {
document.onmousemove = document.onmouseup = null
})
})
window.onresize = (() => {
vnode.style.left = "50%"
vnode.style.top = "50%"
})
}
}
}
9、引用
使用 import 引入
eg: import myDialog from '@/components/myDialog'
这是个弹窗
10、CSS