HTML 在触摸屏上拖放

Muh*_*lik 3 javascript drag-and-drop touch touchmove vue.js

我正在执行一项任务,其中涉及拖动图像并检查其放置位置,如果放置在正确的位置则执行操作。虽然它在任何有鼠标的设备上都可以正常工作,但在触摸屏上却不起作用。如何在触摸屏上实现这一目标。使用 Vuejs 2 或 vanilla javascript

拖动项目

<v-row v-for="(item, iterator) in Activity.drag_items" :key="item.class" :class="[item.class, item.status]" class="drag-item">
   <v-img 
      draggable
      @dragstart='startDrag($event, item, iterator)'
      :src="require(`@/assets/img/activities/activity_2/${item.item_img}`)"
      contain
      :class="item.status"
   ></v-img>
</v-row>
Run Code Online (Sandbox Code Playgroud)

掉落物品

<a @drop='onDrop($event, Activity)' @dragover.prevent @dragenter.prevent></a>
Run Code Online (Sandbox Code Playgroud)

拖动功能

startDrag(evt, item, index){
        evt.dataTransfer.dropEffect = 'move';
        evt.dataTransfer.effectAllowed = 'move';
        evt.dataTransfer.setData('item', JSON.stringify(item));
        evt.dataTransfer.setData('index', index);
    }
Run Code Online (Sandbox Code Playgroud)

掉落功能

onDrop(evt, galaxy_location) {}
Run Code Online (Sandbox Code Playgroud)

小智 5

目前,触摸事件还没有dataTransfer对象。实现此目的的一种方法是使用复制值或数据并根据触摸事件改变它的方法。在我的示例中,我有三种方法来模拟触摸拖放

在触摸启动时,我将所需的引用存储到对象中,这类似于 dataTransfer.setData(),但这里添加的工作是通过删除 touchstart 上的项目来模拟拖放的感觉,并复制一个新元素以跟随您的触摸事件

  touchstartDrag(e, item, arr) {
  // go through origin array
  arr.forEach((el, i) => {
    if (el == item) {
      // store it as reference
      this.touchDragItem = {
        item: item,
        index: i,
        arr: arr
      }
      // remove item in the array, or you can change opacity
      arr.splice(i, 1)
    }
  })
  let image = document.createElement("img"); // Create a new element
  image.setAttribute("id", "image-float");


  // get the image from the stored reference
  image.src = `https://cdn.quasar.dev/img/avatar${this.touchDragItem.item}.jpg`;
  image.width = 100
  image.height = 100

  // position the image to the touch, can be improve to detect the position of touch inside the image
  let left = e.touches[0].pageX;
  let top = e.touches[0].pageY;
  image.style.position = 'absolute'
  image.style.left = left + 'px';
  image.style.top = top + 'px';


  document.getElementById('app').appendChild(image);
},
Run Code Online (Sandbox Code Playgroud)

在touchmove上,这纯粹是为了模拟你从dnd中获得的拖动感觉,获取touchstart中创建的元素并使其跟随你的touchmove

    touchmoveDrag(e) {

  // on touch move or dragging, we get the newly created image element
  let image = document.getElementById('image-float')
  // this will give us the dragging feeling of the element while actually it's a different element
  let left = e.touches[0].pageX;
  let top = e.touches[0].pageY;
  image.style.position = 'absolute'
  image.style.left = left + 'px';
  image.style.top = top + 'px';
  this.touchX = e.touches[0].pageX
  this.touchY = e.touches[0].pageY

},
Run Code Online (Sandbox Code Playgroud)

在触摸端,您可以定义放置功能。因为没有 drop 事件,所以你必须根据 dropzone 手动检测你的触摸,如果它在 dropzone 之外,定义你的逻辑,如果它在 dropzone 之内,按照你定义的 dataTransfer.getData() 相应地执行它

    touchendDrag(e) {
  // remove the image on touch end
  let image = document.getElementById('image-float')
  image.remove()
  // get the dropzone of top and bottom
  let rect1 = document.getElementById('top').getBoundingClientRect();
  let rect2 = document.getElementById('bottom').getBoundingClientRect()
  // to detect the overlap of mouse into the dropzone, as alternative of mouseover
  var overlapTop = !(rect1.right < this.touchX ||
    rect1.left > this.touchX ||
    rect1.bottom < this.touchY ||
    rect1.top > this.touchY)
  // to detect the overlap of mouse into the dropzone bottom
  var overlapBottom = !(rect2.right < this.touchX ||
    rect2.left > this.touchX ||
    rect2.bottom < this.touchY ||
    rect2.top > this.touchY)
  // get the stored reference
  let ex = this.touchDragItem
  // if on touchend the touch is not inside any dropzone, just restore back to the original array
  if (!overlapTop && !overlapBottom) {
    ex.arr.splice(ex.index, 0, ex.item)
  } else {
    if (overlapTop) {
      if (this.top == ex.arr) {
        ex.arr.splice(ex.index, 0, ex.item)
      }
      if (this.top != ex.arr) {
        this.top.push(ex.item)

      }


    }
    if (overlapBottom) {
      if (this.bottom == ex.arr) {
        ex.arr.splice(ex.index, 0, ex.item)
      }
      if (this.bottom != ex.arr) {
        this.bottom.push(ex.item)

      }
    }
  }
  this.touchDragItem = null

},
Run Code Online (Sandbox Code Playgroud)

总的来说,这是一种模拟触摸事件的 dnd API 的简单方法,有很多 vue.js 拖放库可供您使用,具体取决于您的用例,例如sortable.js。但如果你想实现自己的触摸拖动,你可以从这里开始

这是完整的工作示例

  touchstartDrag(e, item, arr) {
  // go through origin array
  arr.forEach((el, i) => {
    if (el == item) {
      // store it as reference
      this.touchDragItem = {
        item: item,
        index: i,
        arr: arr
      }
      // remove item in the array, or you can change opacity
      arr.splice(i, 1)
    }
  })
  let image = document.createElement("img"); // Create a new element
  image.setAttribute("id", "image-float");


  // get the image from the stored reference
  image.src = `https://cdn.quasar.dev/img/avatar${this.touchDragItem.item}.jpg`;
  image.width = 100
  image.height = 100

  // position the image to the touch, can be improve to detect the position of touch inside the image
  let left = e.touches[0].pageX;
  let top = e.touches[0].pageY;
  image.style.position = 'absolute'
  image.style.left = left + 'px';
  image.style.top = top + 'px';


  document.getElementById('app').appendChild(image);
},
Run Code Online (Sandbox Code Playgroud)
    touchmoveDrag(e) {

  // on touch move or dragging, we get the newly created image element
  let image = document.getElementById('image-float')
  // this will give us the dragging feeling of the element while actually it's a different element
  let left = e.touches[0].pageX;
  let top = e.touches[0].pageY;
  image.style.position = 'absolute'
  image.style.left = left + 'px';
  image.style.top = top + 'px';
  this.touchX = e.touches[0].pageX
  this.touchY = e.touches[0].pageY

},
Run Code Online (Sandbox Code Playgroud)
    touchendDrag(e) {
  // remove the image on touch end
  let image = document.getElementById('image-float')
  image.remove()
  // get the dropzone of top and bottom
  let rect1 = document.getElementById('top').getBoundingClientRect();
  let rect2 = document.getElementById('bottom').getBoundingClientRect()
  // to detect the overlap of mouse into the dropzone, as alternative of mouseover
  var overlapTop = !(rect1.right < this.touchX ||
    rect1.left > this.touchX ||
    rect1.bottom < this.touchY ||
    rect1.top > this.touchY)
  // to detect the overlap of mouse into the dropzone bottom
  var overlapBottom = !(rect2.right < this.touchX ||
    rect2.left > this.touchX ||
    rect2.bottom < this.touchY ||
    rect2.top > this.touchY)
  // get the stored reference
  let ex = this.touchDragItem
  // if on touchend the touch is not inside any dropzone, just restore back to the original array
  if (!overlapTop && !overlapBottom) {
    ex.arr.splice(ex.index, 0, ex.item)
  } else {
    if (overlapTop) {
      if (this.top == ex.arr) {
        ex.arr.splice(ex.index, 0, ex.item)
      }
      if (this.top != ex.arr) {
        this.top.push(ex.item)

      }


    }
    if (overlapBottom) {
      if (this.bottom == ex.arr) {
        ex.arr.splice(ex.index, 0, ex.item)
      }
      if (this.bottom != ex.arr) {
        this.bottom.push(ex.item)

      }
    }
  }
  this.touchDragItem = null

},
Run Code Online (Sandbox Code Playgroud)