I am making a small custom drag and drop library, but am running into an issue where mousemove/mouseup events don't fire outside of the window with user-select: none
specified. I found a relevant stackoverflow question, but it refrences old IE/FF versions as the issue, wheras my drag and drop implementation doesn't work in any newer browsers.
Am I doing something wrong?
Relevant code (obviously code is not finished, just trying to get a kinda working implementation atm):
Draggable.vue Mount
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()
I was able to resolve this by attaching the event listener to window
, and not document.body