【问题标题】:Javascript touchmove event not working after event.target moved in DOM in touchstartevent.target 在 touchstart 中移动到 DOM 后,Javascript touchmove 事件不起作用
【发布时间】:2020-12-21 06:23:42
【问题描述】:

我在svg 元素中有几个svg use 元素,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);
}

这对mousedownmousemove 来说就像一个魅力,但对touchstarttouchmove 却不是。完成此操作后,touchmove 事件直到我第二次触摸屏幕才会触发,大概是因为 touchstart 处理程序中的 appendChild() 调用此时没有改变任何内容?

我是否使活动无效?这种情况应该怎么处理?

编辑:

JSFiddle example. //将 append_child 设置为 true/false 以查看行为

【问题讨论】:

  • 请提供minimum reproducible example,即提供简单样本test.svgtest2.svg
  • 如果您有兴趣,@JanStránský 添加了一个工作示例。
  • 有趣。我玩过你的例子,useappendChild 之后,touchevents 不起作用。我试图用setTimout 推迟appendChild,工作得很好,直到DOM 发生变化。但是,它适用于“普通”rect。是例如使用隐形封面并根据拖动的封面调整可见元素的位置是否适合您?
  • 好吧,我在屏幕上有 32 个可拖动元素。我不知道这会带来什么样的性能冲击,但我当然可以尝试一下。不过,我是 javascript 的新手,想知道这些事件发生了什么。您可能会认为,由于处理程序附加到后台,因此不会受到影响...
  • 从描述我不会害怕性能

标签: javascript svg events appendchild touchmove


【解决方案1】:

我用@JanStránský 建议的修改形式规避了这个问题。我放置了一个覆盖整个拖动区域的透明 svg 矩形作为拖动表面,并将其列在 svg 元素列表的末尾。

然后在处理touchstart 时,我使用鼠标位置来确定用户正在选择的这个清晰的 svg 矩形下方的哪个 svg 元素。然后我调用了parentSVG.insertBefore(selected, clear_rect),以便将元素绘制在其他所有内容之上但在此拖动表面之下(因此后续拖动将起作用)。

可拖动元素都布置在(并对齐)网格中,因此鼠标位置 -> 选定元素很容易确定。否则,您可能需要按照建议为每个可拖动元素创建一个清晰的矩形。

这个解决方案似乎阻止了我在元素上方使用 CSS 功能cursor: grab;,因为大的拖动表面挡住了路。也许我会手动实现它。

【讨论】:

    猜你喜欢
    • 2011-04-24
    • 1970-01-01
    • 2016-11-06
    • 2023-03-26
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    相关资源
    最近更新 更多