英文原文出自 Google Deveploers《Creating Fast Buttons for Mobile Web Applications》,由XiaoYi_HD翻譯,並首發於 EsoftMobile.com。如需轉載,請註明譯者及出處信息。html
在 Google,咱們不斷地突破移動 Web 應用可以達到的效果,相似於 HTML5 這類技術讓咱們對原生應用和 Web 應用的界線開始變得模糊。爲了這個目標,咱們開發了一種新技術讓純 HTML 按鈕可以有更快的響應速度。這以前,咱們可能只是爲按鈕或者其餘能夠點擊的元素增長點擊處理,如:git
<button onclick='signUp()'>Sign Up!</button>
使用這種方法存在一個問題就是,移動瀏覽器會在你點擊按鈕後 300ms 才觸發事件,緣由是瀏覽器須要區分你是不是要執行雙擊。可是對於大多數按鈕,咱們並不須要它處理雙擊事件,因此 300ms 的延時時間對於只是想執行點擊事件的用戶來講太長了。咱們最先開發這種技術是在Google Voice mobile web app中,咱們但願可以更加迅速的調用撥號事件。github
該技術涉及一點 JavaScript 的東西來讓按鈕響應觸摸(Touch)事件而不是點擊(Click)事件。觸摸事件響應不會有延時因此感覺會比點擊事件快不少,可是咱們也須要考慮如下幾個問題:web
咱們可以經過檢測 touchstart 和 touchmove 事件來解決前兩個問題,只須要考慮一個一開始在按鈕上就是 touchstart 狀態的觸摸事件,而若是 touchstart 後存在了一個 touchmove,那咱們就不該該處理 touchend 事件。瀏覽器
咱們能夠經過同時給按鈕添加 onclick 處理來解決第三個問題,這樣瀏覽器就會把它當成按鈕並在點擊時出現高亮。咱們 touchend 處理也能保證按鈕仍然很快響應,同時添加 onclick 能夠在不支持觸摸事件的瀏覽器上作爲比較可靠的備用方案。app
在添加觸摸事件的同時添加 onclick 事件又會帶來另外一個討厭的問題,當你點擊按鈕時,點擊 (click) 事件仍然會在 300ms 後執行,咱們能夠經過在 touchstart 事件裏調用 preventDefault 來解決。在 touchstart 中調用 preventDefault 方法會會致使點擊和滑動失效,但咱們又想用戶可以滑動視圖即便一開始是點在按鈕上,因此咱們仍不能接受這種解決方案。接來下咱們想出了一個被咱們叫作點擊破壞者(Click buster)的方案,咱們給 body 添加一個點擊事件監聽(listener),當監聽事件被觸發,咱們會區分點擊是否由咱們已經處理的 tap 事件致使的,若是這樣,咱們才調用 preventDefault 和 stopPropagation。iphone
下面咱們會提供一些咱們實現這個想法的代碼。測試
經過標籤和事件建立一個 FastButtonui
google.ui.FastButton = function(element, handler) { this.element = element; this.handler = handler; element.addEventListener('touchstart', this, false); element.addEventListener('click', this, false); }; google.ui.FastButton.prototype.handleEvent = function(event) { switch(event.type) { case 'touchstart': this.onTouchStart(event); break; case 'touchmove': this.onTouchMove(event); break; case 'touchend': this.onTouchEnd(event); break; case 'click': this.onClick(event); break; } };
保存 touchstart 座標,並開始監聽 touchmove 和 touchend 事件,調用 stopPropagation 來保證其餘操做不會觸發點擊事件。this
google.ui.FastButton.prototype.onTouchStart = function(event) { event.stopPropagation(); this.element.addEventListener('touchend', this, false); document.body.element.addEventListener('touchmove', this, false); this.startX = event.touches[0].clientX; this.startY = event.touches[0].clientY; };
當 touchmove 事件觸發時,檢查用戶是否拖動超過 10px。
google.ui.FastButton.prototype.onTouchMove = function(event) { if (Math.abs(event.touches[0].clientX - this.startX) > 10 || Math.abs(event.touches[0].clientY - this.startY) > 10) { this.reset(); } };
執行真正的點擊事件並在 touchend 事件時避免討厭的 click。
google.ui.FastButton.prototype.onClick = function(event) { event.stopPropagation(); this.reset(); this.handler(event); if (event.type == 'touchend') { google.clickbuster.preventGhostClick(this.startX, this.startY); } }; google.ui.FastButton.prototype.reset = function() { this.element.removeEventListener('touchend', this, false); document.body.removeEventListener('touchmove', this, false); }
調用 preventGhostClick 來破壞在接下來 2.5s 內 x, 移動距離在 25px 內的點擊事件。
google.clickbuster.preventGhostClick = function(x, y) { google.clickbuster.coordinates.push(x ,y); window.setTimeout(google.clickbuster.pop, 2500); }; google.clickbuster.pop = function() { google.clickbuster.coordinates.splice(0, 2); };
若是咱們在給定的半徑和時間內捕獲到了點擊事件,調用 stopPropagation 和 preventDefault。
google.clickbuster.onClick = function(event) { for (var i = 0; i < google.clickbuster.coordinates.length; i += 2) { var x = google.clickbuster.coordinates[i]; var y = google.clickbuster.coordinates[i + 1]; if (Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) { event.stopPropagation(); event.preventDefault(); } } }; document.addEventListener('click', google.clickbuster.onClick, true); google.clickbuster.coordinates = [];
到這裏你應該可以建立快速響應的按鈕了,花一點心思,你可讓它們看起來更像你所面向平臺的原生按鈕。如今已經有一些 JavaScript 庫也提供了這種問題的解決方案,可是到目前爲止咱們沒有發現有提供可靠備選方案和討厭的點擊問題。咱們但願瀏覽器開發者可以在可以解決在不能縮放的頁面上快速響應的問題,事實上咱們已經在 Gingerbread 的瀏覽器上實現了。
測試代碼FastButtonDemo已上傳 github。
Posted by XiaoYi_HD - 6月 27 2013
如需轉載,請註明: 本文來自 Esoft Mobile