从一次报错聊聊 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...

相关文章
相关标签/搜索