Событие touchmove Javascript не работает после того, как event.target перемещен в DOM в touchstart

У меня есть несколько элементов svg use внутри элемента svg с обработчиками событий для touchstart/move/end, прикрепленными к элементу svg. Когда пользователь касается элемента svg use на экране и перемещает палец, элемент перемещается по экрану по желанию.

//Exact code in fiddle is different, this is example
<svg id="parent" viewBox="0 0 1000 1000">
   <use href="test.svg" width="100" height="100" x="100" y="100">
   <use href="test2.svg" width="100" height="100" x="100" y="100">
</svg>
//Exact code in fiddle is different, this is example
let parentSVG = document.getElementById("parent");
parentSVG.addEventListener('touchstart', Handle_DragStart); //mousedown too
parentSVG.addEventListener('touchmove', Handle_Drag); //mousemove too
parentSVG.addEventListener('touchend', Handle_DragEnd); //mouseup too

Проблема в том, что я хочу, чтобы перетаскиваемый элемент всегда рисовался поверх других, а элементы рисовались в порядке DOM (сначала первый элемент в DOM). Чтобы справиться с этим, в моем обработчике событий touchstart я перемещаю элемент, к которому прикоснулся пользователь, в конец списка с помощью appendChild():

//Exact code in fiddle is different, this is example
let mid_move = false;
function Handle_DragStart (event)
{
   //Needed to ignore other touch events while dragging
   if(mid_move)
      return;
   mid_move = true;

   //The event.target is the svg use element. 
   //It is already attached to the parentSVG. 
   //This just moves it to the end of the list of children. 
   parentSVG.appendChild(event.target);
}

Это прекрасно работает для mousedown и mousemove, но не для touchstart и touchmove. После этого событие touchmove не срабатывает, пока я не коснусь экрана во второй раз, предположительно потому, что вызов appendChild() в обработчике touchstart в этот момент ничего не меняет?

Я аннулирую событие? Как мне поступить в этой ситуации?

ИЗМЕНИТЬ:

Пример JSFiddle. //Установите для append_child значение true/false, чтобы увидеть поведение


person P. Mattione    schedule 02.09.2020    source источник
comment
Предоставьте минимальный воспроизводимый пример, т.е. предоставьте простой образец test.svg и test2.svg   -  person Jan Stránský    schedule 02.09.2020
comment
@JanStránský добавил рабочий пример, если вам интересно.   -  person P. Mattione    schedule 03.09.2020
comment
Интересный. Я играл с вашим примером, touchevents не работает для use после appendChild их. Я попытался отложить appendChild с setTimout, хорошо работал до тех пор, пока DOM не изменится. НО, это работает для простого rect. Например использование невидимых обложек и регулировка положения видимых элементов в соответствии с перетаскиваемой обложкой вариант для вас?   -  person Jan Stránský    schedule 03.09.2020
comment
Ну, у меня на экране 32 перетаскиваемых элемента. Я не знаю, что это будет за производительность, но я определенно могу попробовать. Я новичок в javascript, и мне интересно, что происходит с событиями. Вы могли бы подумать, что, поскольку обработчик прикреплен к фону, это не повлияет...   -  person P. Mattione    schedule 04.09.2020
comment
Судя по описанию, я бы не боялся производительности   -  person Jan Stránský    schedule 04.09.2020


Ответы (1)


Я обошел проблему с помощью модифицированной формы предложения @JanStránský. Я поместил прозрачный прямоугольник svg, покрывающий всю область перетаскивания, чтобы он действовал как поверхность перетаскивания, и указал его в конце списка элементов svg.

Затем при обработке touchstart я использовал положение мыши, чтобы определить, какой элемент svg под этим прозрачным прямоугольником svg выбирал пользователь. Затем я вызвал parentSVG.insertBefore(selected, clear_rect), чтобы элемент был нарисован выше всего остального, но ниже этой поверхности перетаскивания (чтобы последующие перетаскивания работали).

Все перетаскиваемые элементы размещены в сетке (и привязаны к ней), поэтому положение мыши → выбранный элемент легко определяется. В противном случае вам может понадобиться один прозрачный прямоугольник для каждого перетаскиваемого элемента, как это было предложено.

Это решение, похоже, не позволяет мне использовать функции CSS cursor: grab; при работе над элементом, поскольку мешает большая поверхность перетаскивания. Возможно, я просто реализую это вручную.

person P. Mattione    schedule 04.09.2020