摘要:定位問(wèn)題根據(jù)調(diào)用棧很快定位到了代碼,源碼定位到之前一位同事寫(xiě)的組件代碼,大概是這樣的部分業(yè)務(wù)代碼報(bào)錯(cuò)的地方部分業(yè)務(wù)代碼發(fā)現(xiàn)是觸發(fā)了事件,因?yàn)闆](méi)有這個(gè)字段,導(dǎo)致拋出異常。它的和鼠標(biāo)事件很像,非常容易遷移。
同步自我的博客,歡迎交流
這篇文章在草稿箱里躺了很久,因?yàn)樽罱钟龅搅讼嚓P(guān)問(wèn)題,于是又整理了一下。請(qǐng)注意這里講的不是 css 的 pointer-events。
起因從某個(gè)月黑風(fēng)高的晚上開(kāi)始,有人發(fā)現(xiàn)我們的 web-app 在 Chrome 模擬器里開(kāi)始出現(xiàn)報(bào)錯(cuò),報(bào)錯(cuò)信息大概就是下面這樣。
VM1023:1 Uncaught TypeError: Cannot read property "0" of undefined
但是只有他的瀏覽器有問(wèn)題,而且對(duì)功能毫無(wú)影響,本著在我的機(jī)器上不復(fù)現(xiàn)的精神(好吧,當(dāng)時(shí)比較忙),這個(gè)問(wèn)題的優(yōu)先級(jí)排的不高,但是后面一段時(shí)間慢慢有人也出現(xiàn)相同的問(wèn)題,于是我開(kāi)始在意這個(gè)問(wèn)題了。
定位問(wèn)題根據(jù)調(diào)用棧很快定位到了代碼,源碼定位到之前一位同事寫(xiě)的組件代碼,大概是這樣的:
dom.on("touchstart pointerdown", function (event) { /*部分業(yè)務(wù)代碼*/ var touch = event.touches[0]; //報(bào)錯(cuò)的地方 /*部分業(yè)務(wù)代碼*/ })
debug 發(fā)現(xiàn)是觸發(fā)了 pointdown 事件,因?yàn)?event 沒(méi)有 touches 這個(gè)字段,導(dǎo)致拋出異常。但是之前用的好好的呀,難道是瀏覽器的 API 變化了?而且我也沒(méi)有了解過(guò) pointerdown 事件,這個(gè)事件是用來(lái)處理什么的呢?于是我?guī)е鴥蓚€(gè)問(wèn)題開(kāi)啟了搜索之旅:
什么是 pointerdown 事件
為什么突然開(kāi)始爆發(fā)錯(cuò)誤
聊聊 pointer events查問(wèn)題,最簡(jiǎn)單的問(wèn)題就是摟一遍 W3C 的官方文檔了。這里簡(jiǎn)單說(shuō)下我的理解。
設(shè)備輸入形式的多樣化在 PC 時(shí)代,我們通過(guò)鼠標(biāo)與屏幕交互,這時(shí)候,我們?cè)O(shè)計(jì)系統(tǒng)時(shí)只需要考慮鼠標(biāo)事件就好了。但是如今,有很多新的設(shè)備,比如智能手機(jī),平板電腦,他們包含了其他的輸入方式,比如觸摸,手寫(xiě)筆,官方也為這些輸入形式都提供了新的事件。
但是對(duì)于開(kāi)發(fā)者來(lái)說(shuō),這是件很麻煩的事,因?yàn)檫@意味著你需要為你的網(wǎng)頁(yè)適配各種事件,比如你要根據(jù)用戶的移動(dòng)來(lái)畫(huà)圖,你需要兼容 PC 和手機(jī),你的代碼可能就會(huì)是下面這樣
dom.addEventListener("mousemove", draw); dom.addEventListener("touchmove", draw);
如果需要兼容更多的輸入設(shè)備呢?比如手寫(xiě)筆,這樣的話代碼就會(huì)很復(fù)雜。而且,為了兼容現(xiàn)有的基于鼠標(biāo)事件的代碼,很多瀏覽器都會(huì)為所有的輸入類(lèi)型觸發(fā)鼠標(biāo)事件(例如在 touchmove 時(shí)觸發(fā) mousemove,我在 Chrome 試驗(yàn)了一下不會(huì)觸發(fā),但是因?yàn)闆](méi)有設(shè)備,手寫(xiě)筆的情況沒(méi)有試),這也會(huì)導(dǎo)致無(wú)法確認(rèn)是否真的是鼠標(biāo)觸發(fā)的事件。
如何兼容多種輸入形式為了解決這一系列的問(wèn)題,W3C 定義了一種新的輸入形式,即 pointer。任何由鼠標(biāo)、觸摸、手寫(xiě)筆或者其他輸入設(shè)備在屏幕上觸發(fā)的接觸,都算是 pointer 事件。
它的 API 和鼠標(biāo)事件很像,非常容易遷移。除了提供鼠標(biāo)事件常用的屬性,比如 clientX,target 等等,還提供了一些用于其他輸入設(shè)備的屬性,比如壓力,接觸面,傾斜角度等等,這樣開(kāi)發(fā)者就可以利用 pointer 事件為所有的輸入設(shè)備開(kāi)發(fā)自己的功能了!
提供的屬性pointer 事件提供了一些特有的事件屬性
pointerId:當(dāng)前指針事件的唯一標(biāo)識(shí),主要是在多點(diǎn)觸控時(shí)標(biāo)識(shí)唯一的一個(gè)輸入源
width:接觸面的寬度
height:接觸面的高度
pressure:接觸的壓力值,范圍是0-1,對(duì)于不支持壓力的硬件,比如鼠標(biāo),按壓時(shí)該值必須為 0.5,否則為 0
tiltX,titltY:手寫(xiě)筆的角度
pointerType:事件類(lèi)型,目前有 mouse,pen,touch,如果是無(wú)法探測(cè)的指針類(lèi)型,則該值為空字符串
isPrimary:用于標(biāo)識(shí)是否是主指針,主要是在多點(diǎn)觸控中生效,開(kāi)發(fā)者也可以通過(guò)忽略非主指針的指針事件來(lái)實(shí)現(xiàn)單點(diǎn)觸控。
如何確定主指針:
鼠標(biāo)輸入:一定是主指針
觸摸輸入:如果 pointerdown 觸發(fā)時(shí)沒(méi)有其他激活的觸摸事件,isPrimary 為 true
手寫(xiě)筆輸入:與觸摸事件類(lèi)似,pointerdown 觸發(fā)時(shí)沒(méi)有其他激活的 pointer 事件
相關(guān)事件事件名稱 | 作用 |
---|---|
pointerover | 與 mouseover 行為一致 |
pointerenter | 與 mouseenter 行為一致 |
pointerdown | 指針進(jìn)入活動(dòng)狀態(tài),比如觸摸了屏幕,類(lèi)似于 touchstart |
pointermove | 指針進(jìn)行了移動(dòng) |
pointerup | 指針取消活動(dòng)狀態(tài),比如手指離開(kāi)了屏幕,類(lèi)似于 touchend |
pointercancel | 類(lèi)似于 touchcancel |
pointerout | 指針離開(kāi)元素邊緣或者離開(kāi)屏幕,類(lèi)似于 mouseout |
pointerleave | 類(lèi)似于 mouseleave |
gotpointercapture | 元素捕獲到指針事件時(shí)觸發(fā) |
lostpointercapture | 指針被釋放時(shí)觸發(fā) |
可以看到,pointer 事件與已知的事件類(lèi)型基本一致,但是有一點(diǎn)區(qū)別:在觸摸屏上,我們可能會(huì)滑動(dòng)屏幕來(lái)觸發(fā)頁(yè)面滾動(dòng),縮放或者刷新,對(duì)于 touch 事件,這時(shí)會(huì)觸發(fā) touchmove,但是對(duì)于 pointer 事件,當(dāng)觸發(fā)這些瀏覽器行為時(shí),你卻會(huì)接收到 pointercancel 事件以便于通知你瀏覽器已經(jīng)接管了你的指針事件。
如何檢測(cè)首先,pointer 事件的支持程度已經(jīng)很不錯(cuò)了,你可以使用 Pointer Events polyfill來(lái)進(jìn)行兼容,也可以自行檢測(cè)
if (window.PointerEvent) { // 支持 } else { // 不支持 }導(dǎo)致問(wèn)題的原因
這時(shí)候,對(duì)于本文一開(kāi)始提到的問(wèn)題就顯而易見(jiàn)了,因?yàn)?point events 是沒(méi)有 touches 這個(gè)屬性的。那么我們還有兩個(gè)問(wèn)題。
為什么之前會(huì)用到 point events?后來(lái)我看了下 zepto 的源碼,在事件處理時(shí)是考慮到了 point event 的,同事之前寫(xiě)的代碼大概是參考了 zepto 的事件系統(tǒng)。
為什么會(huì)突然爆發(fā)這個(gè)問(wèn)題?很簡(jiǎn)答,Chrome 55 開(kāi)始支持這個(gè) API,Chrome 具體的支持信息可以參考官方日志,至于怎么檢測(cè)瀏覽器支持,可以參考上面的內(nèi)容
總結(jié)對(duì)于開(kāi)發(fā)來(lái)說(shuō),一定要鉆進(jìn)去,任何 bug 都是有原因的
代碼報(bào)錯(cuò)應(yīng)該有相應(yīng)的監(jiān)控機(jī)制,讓機(jī)器來(lái)幫我們發(fā)現(xiàn)問(wèn)題,而不是靠人工去干預(yù)
參考
https://www.w3.org/Submission...
https://developers.google.com...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82984.html
摘要:類(lèi)型不同導(dǎo)致的問(wèn)題結(jié)果如下我們發(fā)現(xiàn)當(dāng)為數(shù)字的時(shí)候,是不會(huì)進(jìn)行去重的導(dǎo)致的類(lèi)型轉(zhuǎn)換結(jié)果我們發(fā)現(xiàn)通過(guò)之后都變成了類(lèi)型 array_merge 類(lèi)型不同導(dǎo)致的問(wèn)題 $a = [1=>php,2=>mysql,3=>redis]; $c = [1=>zabbix,2=>mysql]; $d = array_merge($a,$c); var_dump($d); 結(jié)果如下 array(5) {...
摘要:解決開(kāi)發(fā)使用的是的框架,在中配置的是然而,在中,通過(guò)發(fā)現(xiàn)的有兩個(gè)用戶的紀(jì)錄,一個(gè)是,另一個(gè)是空,即當(dāng)使用的用戶是非時(shí),訪問(wèn)的是時(shí),就會(huì)報(bào)這個(gè)錯(cuò)。解決辦法將修改為。。,的,只不過(guò)的配置導(dǎo)致了不同的結(jié)果。 SQLSTATE[HY000] [2002] No such file or directory 解決Trace 開(kāi)發(fā)使用的是PHP的Yii2框架,在config/db.php中配置的h...
閱讀 2625·2023-04-26 03:00
閱讀 1427·2021-10-12 10:12
閱讀 4233·2021-09-22 15:33
閱讀 2959·2021-09-22 15:06
閱讀 1561·2019-08-30 15:44
閱讀 2175·2019-08-30 13:59
閱讀 553·2019-08-30 11:24
閱讀 2451·2019-08-29 17:07