Touching a move event does not work after deleting a Touch Start target

I am trying to implement drag and drop functionality using the following pattern:

  • Sign up for the Pointer Down marker event.
  • When the Down event fires, subscribe to the Move and Up events of the Index window and remove the marker.
  • Follow some steps in move mode.
  • When the event "Up" cancels the subscription to "Move" and "Up".

This works for mouse events, but does not work for Touch events. They do not work after removing the Touch Start target. I tried using Polyfill Pointer Events , but it doesn't work either.

I use Chrome Dev Tools to emulate touch events. See Sample:

initTestBlock('mouse', { start: 'mousedown', move: 'mousemove', end: 'mouseup' }); initTestBlock('touch', { start: 'touchstart', move: 'touchmove', end: 'touchend' }); initTestBlock('touch-no-remove', { start: 'touchstart', move: 'touchmove', end: 'touchend' }, true); function initTestBlock(id, events, noRemove) { var block = document.getElementById(id); var parent = block.querySelector('.parent'); var target = block.querySelector('.target'); target.addEventListener(events.start, function(e) { console.log(e.type); if (!noRemove) { setTimeout(function() { // Remove target target.parentElement.removeChild(target); }, 1000); } function onMove(e) { console.log(e.type); var pt = getCoords(e); parent.style.left = pt.x + 'px'; parent.style.top = pt.y + 'px'; } function onEnd(e) { console.log(e.type); window.removeEventListener(events.move, onMove); window.removeEventListener(events.end, onEnd); } window.addEventListener(events.move, onMove); window.addEventListener(events.end, onEnd); }); } // Returns pointer coordinates function getCoords(e) { if (e instanceof TouchEvent) { return { x: e.touches[0].pageX, y: e.touches[0].pageY }; } return { x: e.pageX, y: e.pageY }; } window.addEventListener('selectstart', function() { return false; }, true); 
 .parent { background: darkred; color: white; width: 10em; height: 10em; position: absolute; } .target { background: orange; width: 4em; height: 4em; } #mouse .parent { left: 0em; } #touch .parent { left: 11em; } #touch-no-remove .parent { left: 22em; } 
 <div id="mouse"> <div class="parent">Mouse events <div class="target">Drag here</div> </div> </div> <div id="touch"> <div class="parent">Touch events <div class="target">Drag here</div> </div> </div> <div id="touch-no-remove"> <div class="parent">Touch (no remove) <div class="target">Drag here</div> </div> </div> 
+5
source share
2 answers

The trick is to hide the element until it touches the touch, but do not delete it. Here is an example (enable Touch mode in Chrome Dev Tools and select a device or use a real device): https://jsfiddle.net/alexanderby/na3rumjg/

 var marker = document.querySelector('circle'); var onStart = function(startEvt) { startEvt.preventDefault(); // Prevent scroll marker.style.visibility = 'hidden'; // Hide target element var rect = document.querySelector('rect'); var initial = { x: +rect.getAttribute('x'), y: +rect.getAttribute('y') }; var onMove = function(moveEvt) { rect.setAttribute('x', initial.x + moveEvt.touches[0].clientX - startEvt.touches[0].clientX); rect.setAttribute('y', initial.y + moveEvt.touches[0].clientY - startEvt.touches[0].clientY); }; var onEnd = function(endEvt) { window.removeEventListener('touchmove', onMove); window.removeEventListener('touchend', onEnd); marker.removeEventListener('touchstart', onStart); marker.parentElement.removeChild(marker); // Remove target element }; window.addEventListener('touchmove', onMove); window.addEventListener('touchend', onEnd); }; marker.addEventListener('touchstart', onStart); 
 <svg> <circle r="20" cx="50" cy="20" cursor="move"/> <rect x="10" y="50" width="80" height="80" /> </svg> 
+2
source

Indeed, according to the documents ,

If the target element is removed from the document, events will still be aimed at it, and therefore, it is not necessary to bubble up to the window or document anymore. If there is a risk of removing an element while it is concerned, it is best to attach the listeners' touch directly to the target.

It turns out that the solution is to attach touchmove and touchend listeners to event.target itself, for example:

 element.addEventListener("touchstart", (event) => { const onTouchMove = () => { // handle touchmove here } const onTouchEnd = () => { event.target.removeEventListener("touchmove", onTouchMove); event.target.removeEventListener("touchend", onTouchEnd); // handle touchend here } event.target.addEventListener("touchmove", onTouchMove); event.target.addEventListener("touchend", onTouchEnd); // handle touchstart here }); 

Even if the event.target element is removed from the DOM, events will continue to fire normally and give the correct coordinates.

+3
source

Source: https://habr.com/ru/post/1234352/


All Articles