【问题标题】:Dragging an element with hammer.js fails on mobile在移动设备上使用hammer.js 拖动元素失败
【发布时间】:2018-07-30 07:11:36
【问题描述】:

我正在开发一个界面,以允许用户使用hammer.js 在屏幕上拖动对象。在桌面浏览器中它可以工作,但在移动设备上,当我开始拖动它时它会短暂工作,然后突然表现得好像事件的客户端坐标突然变为 0,0。

我想拖动一个简单的 SVG 圆圈:

<svg version="1.1" viewBox="0 0 640 480" id="svg" style="width: 640px; height: 480px; top:0px; left: 0px; position: absolute;">
  <circle class="selhan" cx="320" cy="240" r="200" id="circ" 
   style="fill: none; stroke: rgb(0, 0, 0); pointer-events: all; 
   touch-action: none; user-select: none; -webkit-user-drag: none; 
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);">
  </circle>
</svg>

我正在设置一个简单的pan 处理程序:

var circ = document.getElementById("circ")
var Hn1=new Hammer(circ, {/*domEvents:true*/})
Hn1.add( new Hammer.Pan({ direction: Hammer.DIRECTION_ALL, threshold: 0, pointers:1 }) )
var X0,Y0
Hn1.on("panstart", function(e) {
    var ob = e.target
    var cx = ob.getAttribute("cx")
    var cy = ob.getAttribute("cy")
    X0=e.center.x-cx
    Y0=e.center.y-cy
})

Hn1.on("pan", function(e) {
        var ob = e.target
        var X = e.center.x-X0
        var Y = e.center.y-Y0
        ob.setAttribute("cx",X)
        ob.setAttribute("cy",Y)    
})

我创建了一个Fiddle 来演示。在移动设备上,如果我将手指放在圆圈的中心并缓慢移动,我会在短时间内看到圆圈轨迹,但随后中心突然跳到 0,0,而在桌面上,它会跟随指针绕所有天。

我创建了一个Updated Fiddle,它在panstartpancancelpanend 事件发生时显示。我看到的是,当圆圈跳到原点时,我得到了一个 pancancel 事件。为什么我的手指还没有离开屏幕,但我的平移却被取消了?

更陌生的是this version。我所做的只是颠倒跨度的顺序(显示计数器出现了多少次panstartpancancelpanend)。如果跨度在 SVG 之后,那么我突然可以平移圆圈,但只能水平地平移。但如果跨度在之前或不存在,那么在手指移动一小段时间后,平移就会突然取消。好吧,原来是滚动的元素,而不是圆圈.但是,版本 41 在桌面上的行为也很奇怪......当我第一次尝试它时,我根本无法让它响应鼠标事件,但随后它开始工作,然后又停止了,所有这一切只需更改为不同的版本和返回。

更新:为了弄清为什么调用pancancel 回调,我检测了hammer.js 的副本。 PanRecognizer directionTest 函数(第 1778 行)返回 false,导致生成取消。所发生的总是某种形式的“什么都没发生”,导致 hasMoved 为假,或距离为 0(我尝试将阈值设置为 -1,但这只是移动到问题出现的地方),或者方向为 DIRECTION_NONE。

这仍然没有多大意义 - 即使我以足够快的速度平移,我也不应该在两个事件之间获得零移动,即使我缓慢平移我也不会'没想到这会是个问题。

更新 2: 我添加了以下工具:

    Hn1.on("hammer.input",function(ev) {
        console.log("debug",ev)
    })

当我这样做时,我看到一个源事件pointercancel,这表明浏览器正在取消实际上正在使用中间的指针运动。在查看此事件的documentation 时,提到的取消指针事件的四个原因均不适用于这种情况。这是怎么回事?!

【问题讨论】:

  • FWIW 我找到了workaround,尽管我仍然希望更好地描述为什么会发生这种情况,以及可能不是那么笨拙的解决方案。

标签: javascript hammer.js


【解决方案1】:

迈克尔,我遇到了和你一样的问题。我已经在 GitHub 上提交了 bug report 示例和视频。有趣的是,您发现它与浏览器触发的“指针取消”有关,但到目前为止,它还没有帮助我弄清楚如何修补这个问题。你在这件事上有什么进展吗?

作为参考,这个* thread 谈到了同样的问题。不幸的是,到目前为止,HammerJS 的修复都没有对我有用。

编辑: 事实证明,阻止窗口上的默认“touchmove”事件处理将解决页面上任何 SVG 元素的这个问题。这是个好消息,但它也会禁用页面上的所有滚动行为。我所做的是在 SVG 对象上捕获“touchmove”事件,因此其中的任何后代都将正确平移。我还不确定它是否有任何不好的副作用,但到目前为止,这意味着我在 SVG 中的平移终于可以在 Android 浏览器上运行了!

为了完整起见,这里是必要的代码:

const options = { passive: false }; // needed because Chrome has this set to "true" by default for "touchmove" events
    mySVG.addEventListener(
      "touchmove",
      e => e.preventDefault(),
      options
    );

【讨论】:

  • 目前我取得的进展是不使用 Hammer,因为我们真正需要查看的东西类型最终需要的并不真正需要锤子提供的完整手势支持
  • 酷,很高兴你找到了解决办法。
【解决方案2】:

我只记得我只需要添加 jquery.ui.touch-punch.js 就可以在移动设备上正常工作

图书馆:

http://touchpunch.furf.com/

【讨论】:

  • 不确定我是否理解...hammer.js 没有任何其他库要求,例如 jQuery。你是在建议我用 jQuery 替换锤子和触摸拳吗?