1. 程式人生 > >指尖下的js ——多觸式web前端開發之一:對於Touch的處理

指尖下的js ——多觸式web前端開發之一:對於Touch的處理

水果公司的那些small and cute的裝置給我們提供了前所未有的使用者體驗。當用戶在iphone和ipad上運指如飛
的時候,那些使用objective-c寫出優秀應用的開發人員們心裡一定充滿了成就感,因為正是他們(而不是水果
)讓iOS的世界變的豐富多彩。然而對於我們這些以web為自己事業核心的程式設計師來說,這種讓人慾罷不能的多
觸式體驗似乎跟我們關係不大,因為瀏覽器那一小塊地方就是我們和使用者的全部交集了。而許多網站為了讓iOS
的使用者能夠在多觸式體驗下使用自己的服務,都專門花錢開發objective-c的本地程式作為自己web service的客
戶端。 
    其實,對於一個web程式設計師或者一個網站來說,如果你的需求僅僅是讓iPhone/iPad使用者能夠正常使用你的
服務,那現有的html4頁面完全能夠滿足(也許需要一點點重構,但是很容易);如果再往上一點,你需要讓你
的web客戶端看起來像是用objective-c實現的一樣,也並非不可能,只需要將我們熟悉的javascript搬到iOS設
備上來就行。 
    本文從一個多觸式網頁開發初學者的角度,首先簡單介紹一下iOS上的瀏覽器(這裡主要指Safari)所支援的
多觸式事件模型,然後將觸控(Touch)這種簡單的動作升級為手勢(Gestrue),最後將javascript + html + 
css構建的應用脫離瀏覽器,放到iOS裝置的螢幕上成為一個本地link並和植物大戰殭屍放到一起。 
    iOS上的Safari也支援click 和mouseover等傳統的互動事件,只是不推薦在iOS的瀏覽器應用上使用click和
mouseover,因為這兩個事件是為了支援滑鼠點選而設計出來的。Click事件在iOS上會有半秒左右的延遲,原
因是iOS要highlight接收到click的element。而mouseover/out等事件則會被手指的點選觸發。所以,在iOS上
,應當拋棄傳統的互動事件模型而接受一個新的事件模型。Touch事件和更高階的Gesture事件,能讓你的網頁
互動起來像native應用一樣。 
    處理Touch事件能讓你跟蹤使用者的每一根手指的位置。你可以繫結以下四種Touch事件:

touchstart:  // 手指放到螢幕上的時候觸發 
touchmove:  // 手指在螢幕上移動的時候觸發 
touchend:  // 手指從螢幕上拿起的時候觸發 
touchcancel:  // 系統取消touch事件的時候觸發。至於系統什麼時候會取消,不詳。。

Gesture事件則是對touch事件的更高階的封裝,主要處理手指slide、rotate、scale等動作,將在下一篇文章
詳述。 
    在開始描述touch事件之前,需要先描述一下多觸式系統中特有的touch物件(android和iOS乃至nokia最新
的meego系統都模擬了類似的物件,這裡只針對iOS,因為我只有iPad可用於測試。。)。這個物件封裝一次
螢幕觸控,一般來自於手指。它在touch事件觸發的時候產生,可以通過touch event handler的event物件取到
(一般是通過event.changedTouches屬性)。這個物件包括一些重要的屬性: 

client / clientY:// 觸控點相對於瀏覽器視窗viewport的位置 
pageX / pageY:// 觸控點相對於頁面的位置 
screenX /screenY:// 觸控點相對於螢幕的位置 
identifier: // touch物件的unique ID 

CSS程式碼

.spirit {              /* 方塊的class名稱*/
         position: absolute;
         width: 50px;
         height: 50px;
         background-color: red;
}

然後,在body下定義一個接收事件的容器,這裡body的height必須是100%才能佔滿整個viewport: 

Html

<body style=”height: 100%;margin:0;padding:0”>

<div id=”canvas”  style=”position: relative;width:100%;height: 100%;”></div>

</body>

定義touchstart的事件處理函式,並繫結事件:

Javascript程式碼

// define global variable

var canvas = document.getElementById(“canvas”),
       spirit, startX, startY;
    // touch start listener

function touchStart(event) {
         event.preventDefault();
         if (spirit ||! event.touches.length) return;
         var touch = event.touches[0];
         startX = touch.pageX;
         startY = touch.pageY;
         spirit = document.createElement(“div”);
         spirit.className = “spirit”;
         spirit.style.left = startX;
         spirit.style.top = startY;
         canvas.appendChild(spirit);
}

// add touch start listener
canvas.addEventListener(“touchstart”, touchStart, false);

首先,我們將方塊spirit作為一個全域性物件,因為我們現在要測試單根手指所以螢幕上最好只有一個物體在移動

(等會有多觸例項)。在touchStart這個事件處理函式中,我們也首先判斷了是否已經產生了spirit,也就是是
否已經有一個手指放到螢幕上,如果是,直接返回。 
    和傳統的event listener一樣,多觸式系統也會產生一個event物件,只不過這個物件要多出一些屬性,比如
這裡的event.touches,這個陣列物件獲得螢幕上所有的touch。注意這裡的event.preventDefault(),在傳統的
事件處理函式中,這個方法阻止事件的預設動作,觸控事件的預設動作是滾屏,我們不想螢幕動來動去的,所
以先呼叫一下這個函式。我們取第一個touch,將其pageX/Y作為spirit建立時的初始位置。接下來,我們建立
一個div,並且設定className,left,top三個屬性。最後,我們把spirit物件appendChild到容器中。這樣,
當第一根手指放下的時候,一個紅色的,50px見方的方塊就放到螢幕上了。 
    然後,我們要開始處理手指在螢幕上移動的事件: 

Javascript程式碼

function touchMove(event) {
         event.preventDefault();
         if (!spirit || !event.touches.length) return;
         var touch = event.touches[0],
              x = touch.pageX – startX,
              y = touch.pageY – startY;
         spirit.style.webkitTransform = 'translate(' + x + 'px, ' + y + 'px)';     
}

Canvas.addEventListener(“touchmove”, touchMove, false);

在touch move listener中,我們使用webkit特有的css屬性:webkitTransform來移動方塊,這個屬性具體怎麼用請google之。建議構造面向iOS裝置的網頁的時候儘量使用webkit自己的特性,不但炫,更可以直接利用硬體來提高效能。 

    最後,我們處理touchend事件。手指提起的時候方塊從螢幕上移除。

function touchEnd(event) {
         If (!spirit) return;
         canvas.removeChild(spirit);
         spirit = null;
}

canvas.addEventListener(“touchend”, touchEnd, false);

在你的ipad或者iphone上測試一下以上程式碼。如果不出意外的話,一個完整的多觸式web程式就誕生了。。 
這種事件處理模式雖然能夠滿足我們開發多觸式網頁應用的需求,但是start – move – end的流程有點繁瑣,
能不能封裝一些常用的動作讓我們用一個event handler就能解決問題呢。沒錯,Gesture事件就是為了這個目
的設計出來的,它封裝了手指的scale, slide, rotate等常用的動作。不過,下一章我們再來討論這個問題。。 
附件是一個更加複雜一些的例子,每根手指放下的時候都會產生一個不同顏色的方塊,手指動的時候方塊跟著
動,手指提起的時候方塊消失,請下載檢視試用。 
通過附件所包含的例項,我們可以看出一些較為隱蔽的特性。首先,這裡我們沒有再使用event.touches取所有
touch的物件,而是使用event.changedTouches這個陣列,用來取得所有跟本次事件相關的touch。但是,這
裡我發現一個奇怪的特性,不知道是我的ipad有問題還是本來就是這樣,就是在有多根手指放在螢幕上的時候
,如果提起一根手指,touchend事件的changedTouches中會包含所有手指的touch物件,然後,其他幾根留
在螢幕上的手指會重新觸發touchstart,並重新整理所有的touch物件(identifier都不一樣了)。如果這是一個所有
裝置都有的特性,那麼將給程式設計者帶來一些不便,不知道水果為啥要這麼處理。 
對touch event的介紹我們點到為止,這裡給大家推薦兩篇文件: 
1. Safari dom additions reference 
2. Safari web content guide
對於有志於開發多觸式網頁應用的程式設計師來說,apple的developer站點是一個應該經常光顧的地方。