平時咱們在電腦上訪問的網頁,大部分狀況下是用鼠標來控制的。好比說連接跳轉,就是鼠標指針移動到連接文字或圖片的位置,而後點擊一下。又好比說滾動屏幕,滑動一下鼠標滾輪就能夠。css
若是是供手機訪問的網頁呢?這時候的控制就靠觸摸屏了。連接跳轉就是用手指點上去,滾動屏幕則是手指按在屏幕上動一動。html
由於是不一樣的設備(電腦、手機),因此儘管在瀏覽網頁時是相似的控制需求(連接跳轉、滾動屏幕),但就會有不一樣的交互形式。這些交互形式,也是由設備所能提供的輸入方式(鼠標、觸摸屏)決定的。jquery
如今流行的響應式設計的網頁,追求的是隻用一套代碼,也保證網頁在不一樣屏幕尺寸的設備上都具備較好的外觀。然而,這裏的不一樣設備,可能不只僅只是差在屏幕尺寸上,它們提供的輸入方式也可能不一樣。所以,想要開發出跨設備通用的網頁,還要作一點別的事。git
處理用戶的輸入要用到事件。鼠標的話,有咱們熟悉的mouseover
、click
等,觸摸的話,也有touchstart
、touchend
等。不過,這樣看就是要分別對兩種輸入作處理了,大概有點麻煩?若是邏輯也很近似的話,是否是還以爲有點不划算?github
若是能有一類事件,能夠同時處理鼠標、觸摸屏這些「雖不一樣但感受有那麼一點類似」的輸入就行了。對的,能夠有,這就是本文要介紹的Pointer Events了。它已經被W3C加入到推薦規範中。canvas
前面說鼠標、觸摸屏它們「雖不一樣但感受有那麼一點類似」,這實際上是有章可循的。不管是鼠標仍是觸摸屏,其輸入均可以用屏幕上的一個或多個座標點來歸納。Pointer就是描述這種座標點集合的抽象概念,表明此類輸入。除鼠標和觸摸屏以外,還有一種常見的座標類型的輸入,是觸控筆,好比數位板或Surface搭配的筆。顯然,觸控筆也是座標類型,一樣能夠用Pointer來表示。瀏覽器
就這樣,Pointer提取了鼠標(mouse)、觸摸屏(touch)、觸控筆(pen)的共通之處,以方便開發跨設備的Web應用。Pointer雖然是一個抽象,但它包含了鼠標、觸摸屏、觸控筆的所有內容。好比,Pointer支持多點觸摸,並且還有壓力、傾斜度等信息。此外,Pointer還提供具體的輸入類型描述,也就是告訴你某個Pointer表明的究竟是鼠標、觸摸屏仍是觸控筆,以幫助實現針對特定輸入的處理。函數
引入Pointer還有一個做用,就是若是同時有不一樣類型的輸入,能夠更好地去實現符合JavaScript單線程風格的響應。由於輸入事件被統一了,會比較有條理,不容易出錯。post
瞭解Pointer以後,還須要注意一些描述Pointer的相關概念,它們算做術語。這裏介紹兩個最主要的。spa
從名字上看,就是指處於激活狀態(active)的Pointer。實際上,這個詞是指「能夠產生事件」的任意Pointer,這是什麼意思呢?下面這些例子會比較容易理解:
和設備鏈接着的鼠標一直是active。
手指與觸摸屏的屏幕接觸着,認定爲active。
位於數位板的響應距離之內的觸控筆,認定爲active(若是你用過數位板,你必定知道觸控筆只須要懸空在數位板上方必定距離內就能夠控制屏幕上的指針,並不須要觸碰到數位板)。
這個能夠看作在前面的基礎上,更進一步狀態的Pointer。也一樣舉對應的例子:
鼠標有至少一個按鍵按下去了。
手指接觸到觸摸屏。
觸控筆觸碰到數位板(有物理接觸)。
你可能會發現,手指觸摸的例子好像和前面是同樣的。這是由於,就觸摸屏的設備而言,通常是沒有Hover(懸停)狀態一說的。也就是說,對於手指觸摸輸入,通常的認定是,並不能作到在「不產生按下效果」的狀況下移動Pointer。
Pointer雖然是新的概念,但如前文所說,它包含了鼠標、觸摸屏、觸控筆的所有內容。就具體的實現形式來講,它更像是如今經常使用的鼠標事件的擴展。好比,Pointer的pointerdown
事件,正好對應鼠標的mousedown
事件,它們很是近似。
原來的時候你這樣爲DOM元素添加鼠標事件:
elem.addEventListener("mousemove", mousemoveHandler, false);
如今換成Pointer以支持更多類型的輸入,你只須要這樣:
elem.addEventListener("pointermove", pointermoveHandler, false);
就通常的使用而言,須要用到的Pointer事件有pointerover
、pointerenter
、pointerdown
、pointermove
、pointerup
、pointerout
、pointerleave
。它們所有均可以對應上咱們熟悉的鼠標事件。不過,平時很經常使用的click
並不在此列,但沒有關係,用pointerup
來作就能夠。
在事件處理函數裏,會有一個event
對象,包含事件的相關信息。Pointer的event
對象實際上繼承了鼠標的event
對象,而後新增了一部分只讀屬性。其中比較重要的幾個:
這是一個數字,用於分別標識當前處於active狀態的各個Pointer。在任何Pointer的事件處理函數內,均可以依靠這個數字標記來確認處理的是不是同一個Pointer。
字符串,就是前文所說的告訴你這個Pointer是鼠標(mouse)、觸摸屏(touch)仍是觸控筆(pen)。若是是除這些以外的沒法識別的輸入,這個屬性會是空字符串。
邏輯值,表示這個Pointer是不是「主要的」(primary)。請看下文。
前文提到過,Pointer支持多點。因此,這個概念能夠幫助確認哪個是首要的點。具體來講,鼠標是隻能一個的,因此表明鼠標的那個Pointer,必定是primary。而對於觸摸屏或觸控筆,在多點輸入的狀況下,只有「最初」的那一個算做primary。這裏「最初」指的是,在pointerdown
事件發生的時候,沒有其餘同類型(觸摸對觸摸,筆對筆)的active狀態的Pointer存在。
由於一種類型就能夠有一個Primary Pointer,因此能夠有多個Primary Pointer。好比同時有手指觸摸和鼠標指針,它們的Pointer都會被認定爲primary。
通常來講,應用同一時間只響應一個輸入點的狀況比較多,所以能夠利用Pointer事件對象的isPrimary
來忽略掉那些額外的輸入點。
在支持手指觸摸的設備中,一次手指觸摸中的動做,是有默認行爲(default behavior)的。好比,縮放(zooming)和平移(panning,和滾動屏幕scrolling同義)。這些默認行爲,和完整的Pointer事件是不相容的。根據手指的動做,若是被斷定爲觸摸的默認行爲,就不會再按照預想的那樣觸發Pointer的事件。所以,你可能想要在某些範圍內,確保不觸發觸摸的某些默認行爲,保證Pointer事件按照預想進行。
css屬性touch-action
通常用在塊元素上,它的取值分別有:
默認值。容許任何設備支持的默認行爲。
不會觸發任何默認行爲。
只容許「水平方向的平移」這一默認行爲。
只容許「垂直方向的平移」這一默認行爲。
只容許「平移」和「縮放」這兩種默認行爲。設備支持的其餘默認行爲(也就是auto
裏額外的部分)不會觸發。
在手機這樣的觸摸屏設備裏,經過手指平移來滾動瀏覽網頁是很廣泛的,因此應謹慎地用這個屬性來取消部分默認行爲。
根據caniuse上的結果,在默認狀況下,除了IE11及Windows 10的Edge,其餘全部瀏覽器都不支持。
啊?那怎麼投入實用?
相似不少其餘新的技術規範,Pointer Events也有Polyfill,就叫作Pointer Events Polyfill,由jQuery團隊開發,簡稱PEP。
這個Polyfill並不能實現規範的所有內容,而是有些誤差,所以須要注意幾個地方:
一是touch-action
須要用html屬性形式使用。例如:
<canvas width="800" height="600" touch-action="none"></canvas>
二是隻有設置了touch-action
屬性的元素內部,才能觸發Pointer Events。也就是須要偵聽Pointer事件的區域,必定要選至少一個元素加上touch-action
。
這樣設置好以後,就能夠像使用鼠標事件那樣來使用Pointer Events了,好比結合jQuery的使用示例:
$("#canvas").on("pointermove", function(event) { draw(event); });
加上這個Polyfill後,將支持IE10+及其餘各種瀏覽器(包括手機上的)。
並,沒,有,什,麼,關,系,請明確地區分它們。
像連接跳轉、滾動屏幕這樣的簡單響應,電腦和手機上的瀏覽器默認就已經作好了處理,並不須要咱們作什麼。但要作跨設備通用的、更復雜的Web應用,Pointer Events能夠很大程度上簡化對多種輸入方式的處理。
我是由於一次應用開發中不能容忍click
事件在觸摸設備上的延遲,這才找到了Pointer Events。應該說,很贊同Pointer Events的這種化繁爲簡的整合理念,但從它目前的瀏覽器兼容性來看,它還有很遠的路要走。不過,隨着將來更多輸入設備的發展,它有可能會以另外的形式再次入場。
(從新編輯自個人博客,原文地址:http://acgtofe.com/posts/2015/11/pointer-events-for-cross-platform)