使用hammer.js在移动设备上拖动元素失败

3
我正在开发一个界面,使用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,而在桌面上,它一直跟随指针移动。

我创建了一个更新的Fiddle,用于显示panstartpancancelpanend事件发生时的情况。我所看到的是,当圆形跳转到原点时,我会收到一个pancancel事件。为什么我的pan操作会被取消,即使我没有从屏幕上抬起手指?

更奇怪的是this version。我所做的只是颠倒了跟踪panstartpancancelpanend次数的悬挂标签的顺序。如果标签在SVG之后,则突然间我可以移动圆形,但仅限水平移动。但是,如果标签在SVG之前或不存在,则在短时间内指尖移动后,移动操作会突然取消。好吧,事实证明滚动的是元素而不是圆形。但是,在桌面上,版本41也表现得很奇怪……当我第一次尝试时,它根本不响应鼠标事件,但后来它开始工作,然后又停止了,只是通过切换到不同的版本再切换回来就能实现。

更新:为了弄清楚为什么会调用“pancancel”回调函数,我在我的hammer.js副本中进行了检测。PanRecognizer的“directionTest”函数(第1778行)返回false,导致生成取消操作。发生的情况总是某种形式的“没有发生任何事情”,导致“hasMoved”为false,或距离为0(我尝试将阈值设置为-1,但这只是改变了问题出现的位置),或方向为DIRECTION_NONE。
这仍然不太合理-即使我以足够快的速度移动,我也会看到这种情况发生,我不希望这成为问题,即使我移动得很慢。
更新2: 我添加了以下检测:
    Hn1.on("hammer.input",function(ev) {
        console.log("debug",ev)
    })

当我这样做时,我看到一个源事件pointercancel,这表明浏览器正在取消指针运动,而实际上它正在被使用中。在查看文档的过程中,没有提到任何指针事件被取消的四个原因适用于这种情况。这是怎么回事?!

就我个人而言,我已经找到了一个解决方法,尽管我仍然希望能够得到更好的描述为什么会发生这种情况以及可能不那么笨拙的解决方案。 - Michael
2个回答

2

Michael,我遇到了和你一样的问题。我在GitHub上提交了一个错误报告,并提供了示例和视频。有趣的是,你发现这与浏览器触发“pointercancel”有关,但到目前为止,这并没有帮助我找出如何修补此问题。你在这个问题上有任何进展吗?

参考StackOverflow主题讨论了同样的问题。不幸的是,迄今为止,对于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,因为我们实际需要查看的类型不需要 Hammer 提供的全手势支持。 - Michael
很酷,很高兴你找到了解决方法。 - Walmink

0

我刚想起来我只需要添加jquery.ui.touch-punch.js文件,这样在移动设备上就可以正常使用了。

程序库:

http://touchpunch.furf.com/


我不确定我理解了... hammer.js没有像jQuery那样的其他库要求。你是在建议我用jQuery和touch punch替换hammer吗? - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接