События touchmove останавливаются после замены innerHTML
У меня есть веб-страница, которая отслеживает события сенсорного перемещения, позволяя пользователю перетаскивать элемент по экрану - работает отлично.
Я динамически заменяю html внутри движущегося элемента, пока пользователь перемещает его - замена html работает нормально.
Проблема заключается в том, что если пользователь перетаскивает, касаясь внутреннего html (который заменяется), тогда перетаскивание (события touchmove) прекращается, когда этот внутренний html заменяется (до следующего сенсорного запуска).
Слушатель событий находится во внешнем контейнере, а не в HTML, который заменяется, поэтому я думаю, что он должен продолжать захват событий.
Также эта проблема не возникает с событиями mousemove.
Я сделал демо jsfiddle. Использование мыши должно работать нормально, и никаких проблем не возникнет (события mousemove). Эта проблема возникает, когда вы используете сенсорное устройство (или симуляцию касания Chrome: Дополнительные инструменты> Датчики> Сенсорный> Принудительное включение).
https://jsfiddle.net/dmdjvd7e/1/
То же самое, но с использованием jquery: https://jsfiddle.net/a2fwkr4e/6/
В демоверсии вы можете перетащить красный кружок вокруг экрана. Желтое поле внутри круга заменяется каждую секунду. Если вы коснетесь красного (а не желтого), все будет работать правильно. Если вы дотронетесь до желтого, то все будет работать до тех пор, пока желтый блок не будет заменен (каждую секунду), после чего вы не будете перемещать элемент до тех пор, пока вы не нажмете снова.
Это предполагаемое поведение браузера? почему мышиный ход отличается? Есть ли способ обойти это, все еще позволяя мне заменить HTML?
Если я не заменяю внутренний html, а просто изменяю его или просто заменяю текст, а не html-элементы, то проблем не возникает. Тем не менее, я хотел бы иметь возможность заменить HTML (в соответствии с существующими требованиями приложения).
...
Код включен для полноты (так же, как jsfiddle):
CSS / HTML:
<style>
.container {
user-select: none;
background-color: gray;
position: absolute;
top:0;
left:0;
bottom:0;
right:0;
}
.dot {
border-radius: 100%;
background-color: red;
padding: 2em;
margin: -4em 0 0 -4em;
position: absolute;
top: 3em;
left: 3em;
color: blue;
}
.dot div {
font-weight: bold;
color: black;
background-color: yellow;
padding: 2em;
}
</style>
<div class='container'>
<div class='dot'><div class='num'>0</div></div>
</div>
ЯШ:
var eContainer = document.querySelector('.container'),
eDot = document.querySelector('.dot'),
dragActive = false,
val = 0;
var hInterval = setInterval(function() {
++val;
eDot.innerHTML = '<div class="num">' + val + '</div>';
}, 1000);
eContainer.addEventListener('touchstart', dragStart);
eContainer.addEventListener('touchend', dragEnd);
eContainer.addEventListener('touchmove', dragMove);
eContainer.addEventListener('mousedown', dragStart);
eContainer.addEventListener('click', dragEnd);
eContainer.addEventListener('mousemove', dragMove);
function dragStart(e) {
dragActive = true;
}
function dragMove(e) {
if (!dragActive) return;
var posX = e.clientX || (e.touches && e.touches.length ? e.touches[0].pageX : 0),
posY = e.clientY || (e.touches && e.touches.length ? e.touches[0].pageY : 0);
eDot.style.left = posX + 'px';
eDot.style.top = posY + 'px';
}
function dragEnd(e) {
dragActive = false;
}
Протестировано с Chrome 62 и Firefox 56 (оба на Windows 10) и Chrome 60 (Android N), а также Safari/webkit 602.1 (iPhone 6).
1 ответ
Хорошо.. я полагаю, я должен был прочитать спецификацию:
"Целью этого события должен быть тот же Элемент, на котором точка касания началась, когда она впервые была размещена на поверхности, даже если точка касания с тех пор вышла за пределы интерактивной области целевого элемента".
https://www.w3.org/TR/touch-events/
Кроме того, после всего этого набора я обнаружил, что тот же вопрос уже задавался, и у него есть пара ответов: событие Touch Move не срабатывает после удаления цели Touch Start