移動端 Touch 事件的使用與思考(1)

本文主要介紹 TouchEvent 相關的一些對象與屬性如 Touch, TouchList, touhces, targetTouches 等,以及使用的注意點和誤區。javascript

觸摸事件有如下幾種類型:touchstart,touchmove,touchend這三種用的比較多,還有不經常使用的touchcancel事件。固然 MDN上還介紹了touchenter,touchleave事件,具體適用的場景及兼容性如何還未作測試,感興趣的可自行研究。java

js中不一樣的事件類型,event對象包含的屬性也有所差別。咱們先了解幾個TouchEvent涉及的對象。chrome

提示:文中的demo都是在 chrome 模擬器,iPhone6s(iOS9.3.2) safari,iOS微信上運行,安卓的兼容性未作測試數組

Touch

Touch對象表明一個觸點,能夠經過event.touches[0]獲取,每一個觸點包含位置,大小,形狀,壓力大小,和目標 element屬性。瀏覽器

{
    screenX: 511, 
    screenY: 400,//觸點相對於屏幕左邊沿的Y座標
    clientX: 244.37899780273438, 
    clientY: 189.3820037841797,//相對於可視區域
    pageX: 244.37, 
    pageY: 189.37,//相對於HTML文檔頂部,當頁面有滾動的時候與clientX=Y 不等
    force: 1,//壓力大小,是從0.0(沒有壓力)到1.0(最大壓力)的浮點數
    identifier: 1036403715,//一次觸摸動做的惟一標識符
    radiusX: 37.565673828125, //可以包圍用戶和觸摸平面的接觸面的最小橢圓的水平軸(X軸)半徑
    radiusY: 37.565673828125,
    rotationAngle: 0,//它是這樣一個角度值:由radiusX 和 radiusY 描述的正方向的橢圓,須要經過順時針旋轉這個角度值,才能最精確地覆蓋住用戶和觸摸平面的接觸面
    target: {} // 這次觸摸事件的目標element
}

identifier
這個屬性你們可能有疑惑,使用 Chrome 的模擬器發現屢次觸摸動做,值始終不變。用真機測試則不會有問題(我這裏用的safari鏈接mac調試)。每次觸摸包括start,move,end這整個過程,標誌符都不變。下一次觸摸動做開始,標誌符就會變化。微信

screenY clientY
在 safari 中 screenYclientY值是相等的,在iOS微信中兩個數值不等,但單位應該也不同。ide

radiusX radiusY rotationAngle
測試過程當中safari及微信內置瀏覽器都不支持這些屬性,chrome模擬器能夠。測試

TouchList

Touch對象構成的數組,經過event.touches取到。一個Touch對象表明一個觸點,當有多個手指觸摸屏幕時,TouchList就會存儲多個Touch對象,前面說到的identifier就用來區分每一個手指對應的Touch對象。.net

TouchEvent

TouchEvent就是用來描述手指觸摸屏幕的狀態變化事件,除了通常DOM事件中event對像具有的屬性,還有一些特有的屬性。設計

touches

一個TouchList對象,包含當前全部接觸屏幕的觸點的Touch對象,不論 touchstart 事件從哪一個elment上觸發。

targetTouches

也是一個TouchList對象,包含了以下觸點的 Touch 對象:touchstart從當前事件的目標element上觸發

這裏你們可能產生了疑惑,這兩個對象到底有什麼區別?尤爲是咱們使用chrome模擬器中運行 demo,打印兩個對象發現他們實際上是同樣的。
這兩個對象的區別能夠類比event.targetevent.currentTarget 的區別,若是之前沒留意,自行 js 高級程序設計。

咱們先看一個 demo2,來了解 touch 事件的特性。
在線編輯: http://jsrun.net/3XKKp
預覽地址: http://jsrun.net/rtd/3XKKp

你們進行如下兩個操做,觀察控制檯發現了什麼?
操做一:一根手指觸摸藍色box,並滑動,繼續滑動出藍色box
操做二:一根手指觸摸非藍色box區域,而後慢慢滑動到藍色box

你們會發現:操做一中即便滑出藍色box,而touchmovetouchend事件會繼續觸發,touches,targetTouches存儲着相同的 Touch 對象,touchmove事件的目標元素仍然是box。
操做二中相關的 touch 事件都不會觸發。很神奇的是 touchmove 事件,明明在 box 上滑動,卻不會觸發 touchmove 事件。

咱們能夠猜想,touch相關的事件是一個總體,一開始touchstart不可能被觸發,則後續touch事件也不會被觸發。固然你能夠不監聽 touchstart 事件,按照操做一 touchmove,touchend 仍是能夠觸發的。

再看下面這個demo2
在線編輯:http://jsrun.net/XXKKp
訪問地址:http://jsrun.net/rtd/XXKKp

這裏咱們對白色區域body也添加了 touch 事件的監聽,繼續上述 demo1中的兩個操做。
咱們能夠發現:

操做一能夠發現:touch 相關的事件能夠冒泡,觸發了 box,body的touch事件。操做二隻能觸發 body 的touch 事件,和demo1同理。

咱們能夠觀察下操做一的兩個對象TouchEvent.targetTouches,TouchEvent.touches,不管是box仍是body觸發的 touch 事件,他們的存儲的 Touch對象都是相同的,並且 target 都是 box。
接下來進行操做三:

用兩根手指,一根手指觸摸藍色box,另外一根觸摸白色區域,而後滑動。

而後再次比較下targetTouchestouches,就能夠發現他們的不一樣。

changedTouches

也是一個 TouchList 對象,對於 touchstart 事件, 這個 TouchList 對象列出在這次事件中新增長的觸點。對於 touchmove 事件,列出和上一次事件相比較,發生了變化的觸點。對於 touchend ,列出離開觸摸平面的觸點(這些觸點對應已經不接觸觸摸平面的手指)。

touchend這裏要特別注意,touches和targetTouches只存儲接觸屏幕的觸點,要獲取觸點最後離開的狀態要使用changedTouches。

以前也常常用touches[0]來獲取Touch 對象,若是知道了 touches,targetTouches,changedTouches 的不一樣之處。在編寫代碼時能夠更好的選擇使用,程序也能夠更嚴謹。

續篇想研究的問題:

  1. touchmove的觸發頻率問題

  2. 如何斷定用戶是快速滑動(swipe事件)

  3. 如何實現Tap

  4. 一些使用總結或最佳實踐

參考資料

文中如理解有誤,還請多多指出!

相關文章
相關標籤/搜索