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

来解决这个问题