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

如果我有一兩隻額外的手,偵錯觸控互動會簡單得多,但是生物技術離讓我長出額外的手還很遠。

幸運的是,我們可以利用將自訂事件分發到瀏覽器。通常,當我們使用滑鼠(或觸控板、或觸控螢幕、或數位板)時,網頁瀏覽器會產生一個 MouseEvent(或 TouchEventPointerEvent)。但是,與此相反,我們 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 函式庫並不完美,某些類型的事件僅在某些瀏覽器中有效,但它可以協助以可重複的方式觸發滑鼠/觸控/指標事件,並具有可調整的時間,讓開發人員可以將雙手放在除錯工具上。時間模式允許精細控制觸發的事件,允許針對相同的手勢執行較少的程式碼迭代,這反過來意味著對正在發生的事情有更簡單、更好的理解。


一句名言(經常錯誤地歸因於亞伯拉罕·林肯)說

有人問一個樵夫:「如果你只有五分鐘來砍倒一棵樹,你會怎麼做?」他回答說:「我會花前兩分半鐘磨利我的斧頭。」

網頁開發也是如此 - 擁有合適的工具會讓你的任務變得輕鬆得多。

這不僅僅是時間問題。也許從頭開始編寫工具很耗時,但最大的收穫是除錯不再令人沮喪。以前,它是「在觸控螢幕上使用一隻手,仔細觀察除錯工具,不要使用斷點,因為你沒有足夠的手」。現在是「更改 prosthetic-hand 事件的時間,設定斷點,搞定」。

更棒的是,擁有自動化工具意味著 Leaflet 現在具有觸控互動的單元測試。PhantomJS 無頭網頁瀏覽器可以理解 prosthetic-hand 產生的 TouchEvent,並且可以檢查地圖在執行該手勢時是否如預期般運作。

透過進行自動化觸控測試,我們將在 Leaflet 中節省大量時間和頭痛。我們只能希望更多專案能從類似的自動化測試中受益。


不要只是編寫開源程式碼。為大家製作更好的工具。

你的,Iván