Leaflet

一个开源的 JavaScript 库
用于移动友好的交互式地图

← 返回博客文章列表

调试触摸交互

大多数情况下,修复 Leaflet 代码中的错误轻而易举。代码简单易懂(大部分情况下)且结构良好。代码约定和单元测试使新手可以轻松地尝试对核心代码进行一些修改。在过去的几个月里,我们向 Your First PR 的团队发送了一些简单的错误报告 - 我们非常乐意看到新手为 Leaflet 贡献修复!

维护/开发像 Leaflet 这样的 JavaScript 库的一些困难之处在于确保它在所有主要浏览器上都能正常运行。在 Ubuntu 桌面上使用 Firefox 的技术可能会在 Macbook 上的 Safari 中导致故障;在 Windows 10 上的 Edge 中运行的技术可能会在 Android 上的 Chrome 中完全崩溃。

幸运的是,Leaflet 中所有特定于浏览器的 hack 都可以通过查看 代码中的 L.Browser 引用 来轻松查看。

这有时会导致 不太理想的代码

    // On some platforms (notably, chrome on win10 + touchscreen + mouse),
    // the browser doesn't fire touchend/pointerup events but does fire
    // native dblclicks. See #4127.
    if (!L.Browser.edge) {
    	obj.addEventListener('dblclick', handler, false);
    }

浏览器开发人员不止一次地告诉我,浏览器嗅探是错误的,特征检测才是正确的。我的意思是,检测 3D CSS 转换和 HTML5 <video> 支持很容易,但是没有(合理的)方法可以检测浏览器在双击触摸屏时是否会自行触发 dblclick 事件。

调试触摸交互尤其棘手。有时重现触摸交互错误的条件很简单(在同一个位置双击触摸屏),但有时会更具体。在 #3798#3814 中,条件是“用一根手指拖动,然后放下另一根手指并捏合”,而在 #3530 中,条件是“捏合直到 maxZoom 达到,然后进行双指拖动”。

这种错误的问题在于,在受控条件下,它们令人沮丧耗时。想象一下,在使用两只手执行非常具体的触摸手势并同时观察调试器时,同时拥有一个代码编辑器和一个浏览器调试器。然后你想在调试器中检查一个变量,但你不能将手指移动哪怕一个像素,因为那样会运行更多代码并改变状态。

然后,在过去的一个小时里,摇摇晃晃的手机充电器连接器又摇晃了一下,调试器断开了连接,你不得不重新开始。

rage quit

如果我有一两条额外的胳膊,调试触摸交互就会简单得多,但生物技术距离让我长出额外的胳膊还很遥远。

幸运的是,我们可以利用 向浏览器分发自定义事件。通常,当我们使用鼠标(或触控板、触摸屏或数字化仪平板电脑)时,Web 浏览器将生成一个 MouseEvent(或一个 TouchEvent 或一个 PointerEvent)。但我们 JavaScript 程序员不会这样做,而是可以创建一个合成(即伪造)事件,然后将其抛给浏览器,以便它可以将其分发到正在监听事件的任何代码。

不幸的是,创建和分发此类事件很麻烦。触摸手势至少涉及 4 到 8 个事件,按照特定顺序,具有特定的数据,以及特定的时间安排。已经有一些尝试自动执行此操作(我找到的最好的方法是 hammer.js 模拟器),但没有很好的方法可以模拟复杂的自定义触摸手势。

直到现在。

我很自豪地介绍 prosthetic-hand,适用于所有需要额外胳膊来进行 JavaScript 调试的需求。

有了 prosthetic-hand,我现在可以自动执行 Leaflet 网页中的捏合缩放手势。

你还可以看到我无形的指头,作为额外奖励。
Animated screenshot of prosthetic-hand zooming in and out

加载此库后,只需请求一条额外的胳膊(使用特定时间模式)。

var h = new Hand({ timing: 'frame' });

然后长出一些指头。

var f1 = h.growFinger('touch');
var f2 = h.growFinger('touch');

然后移动手指(使用像素坐标和毫秒)。

f1.wait(100).moveTo(250, 200, 0)
	.down().wait(500).moveBy(-200, 0, 1000).wait(500).up().wait(500)
	.down().wait(500).moveBy( 200, 0, 1000).wait(500).up().wait(500);

f2.wait(100).moveTo(350, 200, 0)
	.down().wait(500).moveBy( 200, 0, 1000).wait(500).up().wait(500)
	.down().wait(500).moveBy(-200, 0, 1000).wait(500).up().wait(500);

你可以在 prosthetic-hand 演示网站 中查看这一点。

prosthetic-hand 库并不完美,某些类型的事件只在某些浏览器中有效,但它可以帮助以可重复的方式触发鼠标/触摸/指针事件,并具有可调节的时间安排,使开发人员可以将两只手放在调试器上。时间模式允许对触发的事件进行精细控制,从而减少代码迭代次数,从而使代码更简单,并且更容易了解代码运行机制。


一句著名的话(经常 错误地归因于亚伯拉罕·林肯)说

一个伐木工曾经被问到:“如果你只有五分钟时间砍倒一棵树,你会怎么做?”他回答说:“我会花前两分半钟来磨我的斧头。”

Web 开发也是如此 - 拥有合适的工具会让你的任务变得更加容易。

这不仅仅是时间问题。也许从头开始编写一个工具很耗时,但最大的收益是调试不再令人沮丧。以前是“用手触摸触摸屏,仔细观察调试器,不要使用断点,因为你没有足够的手”。现在是“更改 prosthetic-hand 事件的时间安排,设置一个断点,”。

更棒的是,拥有一个自动化的工具意味着 Leaflet 现在拥有 触摸交互的单元测试。PhantomJS 无头 Web 浏览器可以理解 prosthetic-hand 生成的 TouchEvent,并且可以检查地图在执行该手势时是否按预期运行。

通过拥有自动化的触摸测试,我们将在 Leaflet 中节省大量的时间和精力。我们只能希望更多项目能够从类似的自动化测试中受益。


不要仅仅编写开源代码。为每个人制作更好的工具。

你的,Iván