Currently, there is no direct support for the dataTransfer object in touch events. One workaround is to create methods that handle copying data and modifying it based on touch events. In my example, I demonstrate three methods to simulate drag and drop functionality using touch events.
During a touch start, necessary references are stored in an object, similar to dataTransfer.setData(). To mimic drag and drop behavior, the item is removed on touchstart and a new element is duplicated to follow the touch event.
touchstartDrag(e, item, arr) {
// iterate through the original array
arr.forEach((el, i) => {
if (el == item) {
// store as reference
this.touchDragItem = {
item: item,
index: i,
arr: arr
}
// remove item from the array, or adjust 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 according to the touch, can be enhanced to detect touch position within 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);
},
On touchmove, the goal is to replicate the dragging sensation experienced during drag and drop. The previously created element in touchstart is retrieved and made to follow the touch movement.
touchmoveDrag(e) {
// retrieve the newly created image element while dragging
let image = document.getElementById('image-float')
// simulate the dragging effect by updating the position
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
},
For touch end, where the drop action is defined, manual detection of touch location relative to the drop zone is needed since there is no native drop event. Depending on whether the touch is inside or outside the drop zone, appropriate actions should be executed akin to dataTransfer.getData().
touchendDrag(e) {
// remove the image at touch end
let image = document.getElementById('image-float')
image.remove()
// determine dropzone boundaries
let rect1 = document.getElementById('top').getBoundingClientRect();
let rect2 = document.getElementById('bottom').getBoundingClientRect()
// check for overlap with drop zones
var overlapTop = !(rect1.right < this.touchX ||
rect1.left > this.touchX ||
rect1.bottom < this.touchY ||
rect1.top > this.touchY)
var overlapBottom = !(rect2.right < this.touchX ||
rect2.left > this.touchX ||
rect2.bottom < this.touchY ||
rect2.top > this.touchY)
// retrieve stored reference
let ex = this.touchDragItem
// handle logic based on touch location
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
},
This approach offers a basic implementation to mimic dnd API for touch events. There are numerous Vue.js drag and drop libraries available, such as sortable.js, catering to various use cases. However, if you wish to create your own touch drag functionality, this serves as a starting point.
Here is the complete working example: