從一次報錯聊聊 Point 事件

同步自個人博客,歡迎交流css

這篇文章在草稿箱裏躺了好久,由於最近又遇到了相關問題,因而又整理了一下。請注意這裏講的不是 csspointer-eventsjquery

原由

從某個月黑風高的晚上開始,有人發現咱們的 web-app 在 Chrome 模擬器裏開始出現報錯,報錯信息大概就是下面這樣。git

VM1023:1 Uncaught TypeError: Cannot read property '0' of undefined

可是隻有他的瀏覽器有問題,並且對功能毫無影響,本着在個人機器上不復現的精神(好吧,當時比較忙),這個問題的優先級排的不高,可是後面一段時間慢慢有人也出現相同的問題,因而我開始在乎這個問題了。github

定位問題

根據調用棧很快定位到了代碼,源碼定位到以前一位同事寫的組件代碼,大概是這樣的:web

dom.on('touchstart  pointerdown', function (event) {
        /*部分業務代碼*/
        
        var touch = event.touches[0]; //報錯的地方
        
        /*部分業務代碼*/
})

debug 發現是觸發了 pointdown 事件,由於 event 沒有 touches 這個字段,致使拋出異常。可是以前用的好好的呀,難道是瀏覽器的 API 變化了?並且我也沒有了解過 pointerdown 事件,這個事件是用來處理什麼的呢?因而我帶着兩個問題開啓了搜索之旅:chrome

  1. 什麼是 pointerdown 事件瀏覽器

  2. 爲何忽然開始爆發錯誤app

聊聊 pointer events

查問題,最簡單的問題就是摟一遍 W3C 的官方文檔了。這裏簡單說下個人理解。dom

設備輸入形式的多樣化

在 PC 時代,咱們經過鼠標與屏幕交互,這時候,咱們設計系統時只須要考慮鼠標事件就行了。可是現在,有不少新的設備,好比智能手機,平板電腦,他們包含了其餘的輸入方式,好比觸摸,手寫筆,官方也爲這些輸入形式都提供了新的事件。google

可是對於開發者來講,這是件很麻煩的事,由於這意味着你須要爲你的網頁適配各類事件,好比你要根據用戶的移動來畫圖,你須要兼容 PC 和手機,你的代碼可能就會是下面這樣

dom.addEventListener('mousemove',
  draw);
dom.addEventListener('touchmove',
  draw);

若是須要兼容更多的輸入設備呢?好比手寫筆,這樣的話代碼就會很複雜。並且,爲了兼容現有的基於鼠標事件的代碼,不少瀏覽器都會爲全部的輸入類型觸發鼠標事件(例如在 touchmove 時觸發 mousemove,我在 Chrome 試驗了一下不會觸發,可是由於沒有設備,手寫筆的狀況沒有試),這也會致使沒法確認是否真的是鼠標觸發的事件。

如何兼容多種輸入形式

爲了解決這一系列的問題,W3C 定義了一種新的輸入形式,即 pointer。任何由鼠標、觸摸、手寫筆或者其餘輸入設備在屏幕上觸發的接觸,都算是 pointer 事件。

它的 API 和鼠標事件很像,很是容易遷移。除了提供鼠標事件經常使用的屬性,好比 clientXtarget 等等,還提供了一些用於其餘輸入設備的屬性,好比壓力,接觸面,傾斜角度等等,這樣開發者就能夠利用 pointer 事件爲全部的輸入設備開發本身的功能了!

提供的屬性

pointer 事件提供了一些特有的事件屬性

  • pointerId:當前指針事件的惟一標識,主要是在多點觸控時標識惟一的一個輸入源

  • width:接觸面的寬度

  • height:接觸面的高度

  • pressure:接觸的壓力值,範圍是0-1,對於不支持壓力的硬件,好比鼠標,按壓時該值必須爲 0.5,不然爲 0

  • tiltX,titltY:手寫筆的角度

  • pointerType:事件類型,目前有 mousepentouch,若是是沒法探測的指針類型,則該值爲空字符串

  • isPrimary:用於標識是不是主指針,主要是在多點觸控中生效,開發者也能夠經過忽略非主指針的指針事件來實現單點觸控。
    如何肯定主指針:

    • 鼠標輸入:必定是主指針

    • 觸摸輸入:若是 pointerdown 觸發時沒有其餘激活的觸摸事件,isPrimarytrue

    • 手寫筆輸入:與觸摸事件相似,pointerdown 觸發時沒有其餘激活的 pointer 事件

相關事件

事件名稱 做用
pointerover mouseover 行爲一致
pointerenter mouseenter 行爲一致
pointerdown 指針進入活動狀態,好比觸摸了屏幕,相似於 touchstart
pointermove 指針進行了移動
pointerup 指針取消活動狀態,好比手指離開了屏幕,相似於 touchend
pointercancel 相似於 touchcancel
pointerout 指針離開元素邊緣或者離開屏幕,相似於 mouseout
pointerleave 相似於 mouseleave
gotpointercapture 元素捕獲到指針事件時觸發
lostpointercapture 指針被釋放時觸發

能夠看到,pointer 事件與已知的事件類型基本一致,可是有一點區別:在觸摸屏上,咱們可能會滑動屏幕來觸發頁面滾動,縮放或者刷新,對於 touch 事件,這時會觸發 touchmove,可是對於 pointer 事件,當觸發這些瀏覽器行爲時,你卻會接收到 pointercancel 事件以便於通知你瀏覽器已經接管了你的指針事件。

如何檢測

首先,pointer 事件的支持程度已經很不錯了,你可使用 Pointer Events polyfill來進行兼容,也能夠自行檢測

if (window.PointerEvent) {
    // 支持
} else {
  // 不支持
}

致使問題的緣由

這時候,對於本文一開始提到的問題就顯而易見了,由於 point events 是沒有 touches 這個屬性的。那麼咱們還有兩個問題。

爲何以前會用到 point events

後來我看了下 zepto 的源碼,在事件處理時是考慮到了 point event 的,同事以前寫的代碼大概是參考了 zepto 的事件系統。

爲何會忽然爆發這個問題?

很簡答,Chrome 55 開始支持這個 API,Chrome 具體的支持信息能夠參考官方日誌,至於怎麼檢測瀏覽器支持,能夠參考上面的內容

總結

  1. 對於開發來講,必定要鑽進去,任何 bug 都是有緣由的

  2. 代碼報錯應該有相應的監控機制,讓機器來幫咱們發現問題,而不是靠人工去幹預

參考
https://www.w3.org/Submission...
https://developers.google.com...

相關文章
相關標籤/搜索