Mousemove 未在 window 外触发,用户 -select:none
Mousemove not firing outside window with user-select:none
我正在制作一个小型自定义拖放库,但 运行 遇到一个问题,即 mousemove/mouseup 事件不会在 window 之外触发 user-select: none
指定的。我找到了一个 relevant Whosebug question,但它引用了旧的 IE/FF 版本作为问题,而我的拖放实现在任何较新的浏览器中都不起作用。
我是不是做错了什么?
相关代码(显然代码还没有完成,只是想得到一个有点工作的实现 atm):
Draggable.vue 坐骑
this.$el.addEventListener('mousedown', (e) => {
if (e.buttons === 1) {
this.mouseStart = {
x: e.clientX,
y: e.clientY,
}
this.$el.addEventListener('mousemove', onMouseMove)
this.$el.addEventListener('mouseup', onMouseUp)
}
})
const onMouseMove = (e) => {
if (this.mouseStart) {
if (!dnd.dragging && Math.abs(this.mouseStart.x - e.clientX) > 2 ||
Math.abs(this.mouseStart.y - e.clientY) > 2
) {
dnd.startDrag(
{
x: this.mouseStart.x,
y: this.mouseStart.y,
},
this.$el
)
this.mouseStart = null
}
}
}
const onMouseUp = (e) => {
this.$el.removeEventListener('mousemove', onMouseMove)
this.$el.removeEventListener('mouseup', onMouseUp)
this.mouseStart = null
}
Dnd.js
class Dnd extends EventEmitter {
dragging = false
mouseStartPos = null
dragEle = null
dragEleStartPos = null
ghostComp = null
onMouseUp = () => {
this.stopDrag()
}
onMouseMove = (e) => {
this.dragEle.style.top =
this.dragEleStartPos.y + e.clientY - this.mouseStartPos.y + 'px'
this.dragEle.style.left =
this.dragEleStartPos.x + e.clientX - this.mouseStartPos.x + 'px'
}
startDrag(ctx, comp) {
this.ghostComp = comp
this.mouseStartPos = {
x: ctx.x,
y: ctx.y,
}
this.dragging = true
this.dragEle = this.createDragElement(comp)
document.body.addEventListener('mouseup', this.onMouseUp)
document.body.addEventListener('mousemove', this.onMouseMove)
this.ghostComp.classList.add('dnd-ghost')
}
endDrag() {
this.dragEle.remove()
this.ghostComp.classList.remove('dnd-ghost')
this.dragging = false
this.mouseStartPos = null
this.dragEle = null
this.ghostComp = null
}
stopDrag() {
document.body.removeEventListener('mouseup', this.onMouseUp)
document.body.removeEventListener('mousemove', this.onMouseMove)
this.dragEle.classList.add('dnd-transition')
this.dragEle.style.top = this.dragEleStartPos.y + 'px'
this.dragEle.style.left = this.dragEleStartPos.x + 'px'
setTimeout(this.endDrag.bind(this), 500)
}
createDragElement(node) {
const cln = node.cloneNode(true)
cln.classList.add('dnd-dragging')
const rect = node.getBoundingClientRect()
document.body.appendChild(cln)
cln.style.top = rect.top + 'px'
cln.style.left = rect.left + 'px'
cln.style.width = rect.width + 'px'
cln.style.height = rect.height + 'px'
this.dragEleStartPos = { x: rect.left, y: rect.top }
return cln
}
}
export default new Dnd()
我能够通过将事件侦听器附加到 window
而不是 document.body
来解决这个问题
我正在制作一个小型自定义拖放库,但 运行 遇到一个问题,即 mousemove/mouseup 事件不会在 window 之外触发 user-select: none
指定的。我找到了一个 relevant Whosebug question,但它引用了旧的 IE/FF 版本作为问题,而我的拖放实现在任何较新的浏览器中都不起作用。
我是不是做错了什么?
相关代码(显然代码还没有完成,只是想得到一个有点工作的实现 atm):
Draggable.vue 坐骑
this.$el.addEventListener('mousedown', (e) => {
if (e.buttons === 1) {
this.mouseStart = {
x: e.clientX,
y: e.clientY,
}
this.$el.addEventListener('mousemove', onMouseMove)
this.$el.addEventListener('mouseup', onMouseUp)
}
})
const onMouseMove = (e) => {
if (this.mouseStart) {
if (!dnd.dragging && Math.abs(this.mouseStart.x - e.clientX) > 2 ||
Math.abs(this.mouseStart.y - e.clientY) > 2
) {
dnd.startDrag(
{
x: this.mouseStart.x,
y: this.mouseStart.y,
},
this.$el
)
this.mouseStart = null
}
}
}
const onMouseUp = (e) => {
this.$el.removeEventListener('mousemove', onMouseMove)
this.$el.removeEventListener('mouseup', onMouseUp)
this.mouseStart = null
}
Dnd.js
class Dnd extends EventEmitter {
dragging = false
mouseStartPos = null
dragEle = null
dragEleStartPos = null
ghostComp = null
onMouseUp = () => {
this.stopDrag()
}
onMouseMove = (e) => {
this.dragEle.style.top =
this.dragEleStartPos.y + e.clientY - this.mouseStartPos.y + 'px'
this.dragEle.style.left =
this.dragEleStartPos.x + e.clientX - this.mouseStartPos.x + 'px'
}
startDrag(ctx, comp) {
this.ghostComp = comp
this.mouseStartPos = {
x: ctx.x,
y: ctx.y,
}
this.dragging = true
this.dragEle = this.createDragElement(comp)
document.body.addEventListener('mouseup', this.onMouseUp)
document.body.addEventListener('mousemove', this.onMouseMove)
this.ghostComp.classList.add('dnd-ghost')
}
endDrag() {
this.dragEle.remove()
this.ghostComp.classList.remove('dnd-ghost')
this.dragging = false
this.mouseStartPos = null
this.dragEle = null
this.ghostComp = null
}
stopDrag() {
document.body.removeEventListener('mouseup', this.onMouseUp)
document.body.removeEventListener('mousemove', this.onMouseMove)
this.dragEle.classList.add('dnd-transition')
this.dragEle.style.top = this.dragEleStartPos.y + 'px'
this.dragEle.style.left = this.dragEleStartPos.x + 'px'
setTimeout(this.endDrag.bind(this), 500)
}
createDragElement(node) {
const cln = node.cloneNode(true)
cln.classList.add('dnd-dragging')
const rect = node.getBoundingClientRect()
document.body.appendChild(cln)
cln.style.top = rect.top + 'px'
cln.style.left = rect.left + 'px'
cln.style.width = rect.width + 'px'
cln.style.height = rect.height + 'px'
this.dragEleStartPos = { x: rect.left, y: rect.top }
return cln
}
}
export default new Dnd()
我能够通过将事件侦听器附加到 window
而不是 document.body