Vue 自定义指令实现组件可拖拽

1,125 阅读1分钟

Vue 自定义拖拽指令(在 main.js 文件写入以下代码)

Vue.directive('drag', function (el) {
  const oDiv = el // 当前元素
  document.onselectstart = () => {
    return false
  }
  oDiv.onmousedown = e => { // 鼠标按下时的鼠标所在的X,Y坐标
    // 鼠标按下,计算当前元素距离可视区的距离
    const disX = e.clientX - oDiv.offsetLeft
    const disY = e.clientY - oDiv.offsetTop
    document.onmousemove = e => {
      // 通过事件委托,计算移动的距离
      // 因为浏览器里并不能直接取到并且使用clientX、clientY,所以使用事件委托在内部做完赋值
      const l = e.clientX - disX
      const t = e.clientY - disY
      // 计算移动当前元素的位置,并且给该元素样式中的left和top值赋值
      oDiv.style.left = l + 'px'
      oDiv.style.top = t + 'px'
    }
    document.onmouseup = e => { // 鼠标抬起,清空之前所在的位置,新拖拽的位置已生成并赋值
      document.onmousemove = null
      document.onmouseup = null
    }
    // return false不加的话可能导致黏连,拖到一个地方时div粘在鼠标上不下来,相当于onmouseup失效
    return false
  }
}

使用的时候跟其他 Vue 指令一样,在绑定的组件中使用 v-drag 即可

<div class="video-pop" v-drag>

因为该方法会导致整个组件都是拖拽区域,因此我在使用的时候做了一些修改,将 onmousedown 的事件,绑定在组件的第一个子元素中,具体情况看实际使用来调整

Vue.directive('drag', function (el) {
  const oDiv = el
  document.onselectstart = () => {
    return false
  }
  oDiv.onmousedown = e => { 
    const disX = e.clientX - oDiv.offsetLeft
    const disY = e.clientY - oDiv.offsetTop
    document.firstChild.onmousemove = e => {  // 就是这里,将 onmousedown 的事件,绑定在组件的第一个子元素中
      const l = e.clientX - disX
      const t = e.clientY - disY
      oDiv.style.left = l + 'px'
      oDiv.style.top = t + 'px'
    }
    document.onmouseup = e => {
      document.onmousemove = null
      document.onmouseup = null
    }
    return false
  }
}