VUE2元素拖动指令

169 阅读2分钟

移动端

export default {
  bind: function (el, binding) {
    let isDragging = false
    let startX,
      startY,
      deltaX,
      deltaY,
      x,
      y,
      isXMove = true,
      isYMove = true
    // el.style.position="absolute"|"fixed" 元素需要是定位的,也可以在这直接强制加
    // 通过使用时携带的修饰符限定只能横向拖动或者纵向拖动
    if (binding.modifiers.x) {
      // 只有横向移动
      isYMove = false
    }
    if (binding.modifiers.y) {
      // 只有纵向移动
      isXMove = false
    }
    el.ontouchstart = (e) => {
      isDragging = true
      startX = e.touches[0].clientX - el.offsetLeft
      startY = e.touches[0].clientY - el.offsetTop
      el.ontouchmove = moveHandler
      el.ontouchend = upHandler
    }
    function moveHandler(e) {
      e.preventDefault() //阻止默认的处理方式(阻止下拉滑动的效果)
      e.stopPropagation()
      if (isDragging) {
        deltaX = e.touches[0].clientX - startX
        deltaY = e.touches[0].clientY - startY
        // 处理元素只能在视图内移动,不然移动到屏幕外,元素就消失了,也移动不回来了
        deltaX = Math.max(0, deltaX)
        deltaY = Math.max(0, deltaY)
        deltaX = Math.min(e.view.innerWidth - el.offsetWidth, deltaX)
        deltaY = Math.min(e.view.innerHeight - el.offsetHeight, deltaY)
        x = deltaX + 'px'
        y = deltaY + 'px'
        if (isXMove) {
          el.style.left = x
        }
        if (isYMove) {
          el.style.top = y
        }
      }
    }
    function upHandler(e) {
      e.preventDefault() //阻止默认的处理方式(阻止下拉滑动的效果)
      e.stopPropagation()
      isDragging = false
      el.ontouchmove = null
      el.ontouchend = null
    }
  }
}

// 使用
<div v-draggle>添加</div>
<div v-draggle.x>添加</div>
<div v-draggle.y>添加</div>

PC端

export default {
  bind: function (el, binding) {
    let isDragging = false
    let startX,
      startY,
      deltaX,
      deltaY,
      x,
      y,
      isXMove = true,
      isYMove = true,
      dragDom = el
    if (binding.modifiers.x) {
      // 只有横向移动
      isYMove = false
    }
    if (binding.modifiers.y) {
      // 只有纵向移动
      isXMove = false
    }
    el.onmousedown = (e) => {
      isDragging = true
      // 如果当前操作当前元素,移动父级元素
      if (binding.modifiers.parent) {
        dragDom = el.parentNode
      }
      // 禁止选中文字,防止拖拽时弹框粘鼠标
      document.onselectstart = function () {
        return false
      }
      startX = e.x - dragDom.offsetLeft // 鼠标点击在dom上到dom左边的距离
      startY = e.y - dragDom.offsetTop // 鼠标点击在dom上到dom上边的距离
      el.onmousemove = moveHandler
      el.onmouseup = upHandler
    }
    function moveHandler(e) {
      e.preventDefault() //阻止默认的处理方式(阻止下拉滑动的效果)
      e.stopPropagation()
      if (isDragging) {
        deltaX = e.x - startX // 当前鼠标的位置 - 到dom左边的距离 = left
        deltaY = e.y - startY // 当前鼠标的位置 - 到dom上边的距离 = top
        deltaX = Math.max(0, deltaX) // 不能超出屏幕左边
        deltaY = Math.max(0, deltaY) // 不能超出屏幕上边
        deltaX = Math.min(window.innerWidth - dragDom.clientWidth, deltaX) // 不能超出屏幕右边 即left < (屏幕宽 - 元素宽)
        deltaY = Math.min(window.innerHeight - dragDom.clientHeight, deltaY) // 不能超出屏幕下边 即top < (屏幕高 - 元素高)
        x = deltaX + 'px'
        y = deltaY + 'px'
        if (isXMove) {
          dragDom.style.left = x
        }
        if (isYMove) {
          dragDom.style.top = y
        }
      }
    }
    function upHandler(e) {
      e.preventDefault() //阻止默认的处理方式(阻止下拉滑动的效果)
      e.stopPropagation()
      isDragging = false
      el.onmousemove = null
      el.onmouseup = null
    }
    document.onmouseup = function () {
      el.onmousemove = null
      el.onmouseup = null
      // 在抬起鼠标之后,取消禁用选择文字
      document.onselectstart = function () {
        return true
      }
    }
  }
}


// 使用
<div v-draggle>添加</div>
<div v-draggle.x>添加</div>
<div v-draggle.y>添加</div>
<div>
    <div v-draggle.parent>添加</div>
</div>

注:最后最好还是统一一下,时间不一样,本质上逻辑是一样的