2015-10-23 26 views
5

Próbuję zaimplementować funkcjonalność przeciągania jak przy użyciu następnego wzoru:dotykowy Move zdarzenie nie ognia po tarczy dotykowy start jest usuwany

  • Subskrybuj znaczników zdarzeń wskaźnik w dół.
  • Po uruchomieniu zdarzenia Down należy subskrybować zdarzenia Window Move and Up i usunąć znaczniki.
  • Wykonaj niektóre czynności podczas przenoszenia.
  • Po uruchomieniu zdarzenia Up up anuluj subskrypcję Move and Up.

Działa w przypadku zdarzeń myszy, ale nie działa w przypadku zdarzeń dotykowych. Nie strzelają po usunięciu elementu Touch Start target. Próbowałem użyć Pointer Events Polyfill, ale to też nie działa.

Używam narzędzi Chrome Dev do emulacji wydarzeń dotykowych. Zobacz próbkę:

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>

+0

Mam powiązany problem. Czy znalazłeś rozwiązanie w międzyczasie? –

+0

@SebastianvomMeer Zobacz moją odpowiedź http://stackoverflow.com/a/34980275/4137472 –

Odpowiedz

2

Sztuką jest ukrycie elementu aż do wykończenia dotykowy poruszać, ale nie żeby go usunąć. Oto przykład (włączyć tryb próbkowania Chrome Dev Narzędzia i wybierz jakieś urządzenie lub używać urządzenia fizycznego): 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>

3

Rzeczywiście, according to the docs,

Jeśli element docelowy zostanie usunięty z dokumentu, zdarzenia będą nadal kierowane na niego, a więc niekoniecznie będą bańkami do okna lub dokument już. Jeśli istnieje jakiekolwiek ryzyko usunięcia elementu podczas jego dotykania, najlepszą praktyką jest podłączenie słuchaczy dotykowych bezpośrednio do celu.

Okazuje się, że rozwiązaniem jest dołączenie touchmove i touchend słuchaczy do samego event.target, na przykład:

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 
}); 

Nawet jeśli element event.target jest usuwany z DOM, imprezy będzie nadal na ogień normalnie i podaj prawidłowe współrzędne.

+1

To uratowało mój dzień! :RE – raeffs