通过一次报错详细谈谈Point事件


Posted in Javascript onMay 17, 2018

前言

这篇文章在草稿箱里躺了很久,因为最近又遇到了相关问题,于是又整理了一下。请注意这里讲的不是 css 的 pointer-events。下面话不都说了,来一起看看详细的介绍吧。

起因

从某个月黑风高的晚上开始,有人发现我们的 web-app 在 Chrome 模拟器里开始出现报错,报错信息大概就是下面这样。

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

但是只有他的浏览器有问题,而且对功能毫无影响,本着在我的机器上不复现的精神(好吧,当时比较忙),这个问题的优先级排的不高,但是后面一段时间慢慢有人也出现相同的问题,于是我开始在意这个问题了。

定位问题

根据调用栈很快定位到了代码,源码定位到之前一位同事写的组件代码,大概是这样的:

dom.on('touchstart pointerdown', function (event) {
 /*部分业务代码*/
 var touch = event.touches[0]; //报错的地方
 /*部分业务代码*/
})

debug 发现是触发了 pointdown 事件,因为 event 没有 touches 这个字段,导致抛出异常。但是之前用的好好的呀,难道是浏览器的 API 变化了?而且我也没有了解过 pointerdown 事件,这个事件是用来处理什么的呢?于是我带着两个问题开启了搜索之旅:

  • 什么是 pointerdown 事件
  • 为什么突然开始爆发错误

聊聊 pointer events

查问题,最简单的问题就是搂一遍 W3C 的官方文档了。这里简单说下我的理解。

设备输入形式的多样化

在 PC 时代,我们通过鼠标与屏幕交互,这时候,我们设计系统时只需要考虑鼠标事件就好了。但是如今,有很多新的设备,比如智能手机,平板电脑,他们包含了其他的输入方式,比如触摸,手写笔,官方也为这些输入形式都提供了新的事件。

但是对于开发者来说,这是件很麻烦的事,因为这意味着你需要为你的网页适配各种事件,比如你要根据用户的移动来画图,你需要兼容 PC 和手机,你的代码可能就会是下面这样

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

如果需要兼容更多的输入设备呢?比如手写笔,这样的话代码就会很复杂。而且,为了兼容现有的基于鼠标事件的代码,很多浏览器都会为所有的输入类型触发鼠标事件(例如在 touchmove 时触发 mousemove,我在 Chrome 试验了一下不会触发,但是因为没有设备,手写笔的情况没有试),这也会导致无法确认是否真的是鼠标触发的事件。

如何兼容多种输入形式

为了解决这一系列的问题,W3C 定义了一种新的输入形式,即 pointer。任何由鼠标、触摸、手写笔或者其他输入设备在屏幕上触发的接触,都算是 pointer 事件。

通过一次报错详细谈谈Point事件

它的 API 和鼠标事件很像,非常容易迁移。除了提供鼠标事件常用的属性,比如 clientX,target 等等,还提供了一些用于其他输入设备的属性,比如压力,接触面,倾斜角度等等,这样开发者就可以利用 pointer 事件为所有的输入设备开发自己的功能了!

提供的属性

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

  • pointerId:当前指针事件的唯一标识,主要是在多点触控时标识唯一的一个输入源
  • width:接触面的宽度
  • height:接触面的高度
  • pressure:接触的压力值,范围是0-1,对于不支持压力的硬件,比如鼠标,按压时该值必须为 0.5,否则为 0
  • tiltX,titltY:手写笔的角度
  • pointerType:事件类型,目前有 mouse,pen,touch,如果是无法探测的指针类型,则该值为空字符串
  • isPrimary:用于标识是否是主指针,主要是在多点触控中生效,开发者也可以通过忽略非主指针的指针事件来实现单点触控。

如何确定主指针:

鼠标输入:一定是主指针

触摸输入:如果 pointerdown 触发时没有其他激活的触摸事件,isPrimary 为 true

手写笔输入:与触摸事件类似,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 具体的支持信息可以参考官方日志,至于怎么检测浏览器支持,可以参考上面的内容

总结

对于开发来说,一定要钻进去,任何 bug 都是有原因的

代码报错应该有相应的监控机制,让机器来帮我们发现问题,而不是靠人工去干预

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

参考

  • https://www.w3.org/Submission/pointer-events/
  • https://developers.google.com/web/updates/2016/10/pointer-events
Javascript 相关文章推荐
js通过googleAIP翻译PHP系统的语言配置的实现代码
Oct 17 Javascript
JavaScript中的style.display属性操作
Mar 27 Javascript
利用JQuery和Servlet实现跨域提交请求示例分享
Feb 12 Javascript
jquery实现弹出div,始终显示在屏幕正中间的简单实例
Mar 08 Javascript
jQuery 1.9使用$.support替代$.browser的使用方法
May 27 Javascript
JavaScript实现显示函数调用堆栈的方法
Apr 21 Javascript
微信小程序 本地存储及登录页面处理实例详解
Jan 11 Javascript
详解AngularJs ui-router 路由的简单介绍
Apr 26 Javascript
微信小程序之网络请求简单封装实例详解
Jun 28 Javascript
Vue页面骨架屏的实现方法
May 22 Javascript
vue 使用自定义指令实现表单校验的方法
Aug 28 Javascript
js实现浏览器打印功能的示例代码
Jul 15 Javascript
AngularJS日期格式化常见操作实例分析
May 17 #Javascript
Node 升级到最新稳定版的方法分享
May 17 #Javascript
Angular实现模版驱动表单的自定义校验功能(密码确认为例)
May 17 #Javascript
AngularJS自定义过滤器用法经典实例总结
May 17 #Javascript
JS 实现分页打印功能
May 16 #Javascript
使用vue-cli导入Element UI组件的方法
May 16 #Javascript
JS 使用 window对象的print方法实现分页打印功能
May 16 #Javascript
You might like
模拟xcopy的函数
2006/10/09 PHP
树型结构列出指定目录里所有文件的PHP类
2006/10/09 PHP
PHP 缓存实现代码及详细注释
2010/05/16 PHP
php数据库抽象层 PDO
2011/05/07 PHP
php实现的zip文件内容比较类
2014/09/24 PHP
php使用GD库创建图片缩略图的方法
2015/06/10 PHP
laravel批量生成假数据的方法
2019/10/09 PHP
jQuery下通过replace字符串替换实现大小图片切换
2012/05/22 Javascript
js 实现菜单左右滚动显示示例介绍
2013/11/21 Javascript
Select下拉框模糊查询功能实现代码
2016/07/22 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
又一款MVVM组件 构建自己的Vue组件(2)
2017/03/13 Javascript
基于JavaScript实现选项卡效果
2017/07/21 Javascript
angular基于ng-alain定义自己的select组件示例
2018/02/23 Javascript
webpack 3.X学习之多页面打包的方法
2018/09/04 Javascript
axios 封装上传文件的请求方法
2018/09/26 Javascript
Vue.js实现可排序的表格组件功能示例
2019/02/19 Javascript
JavaScript实现移动端拖动元素
2020/11/24 Javascript
jQuery实现手风琴特效
2021/01/11 jQuery
深入理解Python异常处理的哲学
2019/02/01 Python
Pycharm 字体大小调整设置的方法实现
2019/09/27 Python
使用 pytorch 创建神经网络拟合sin函数的实现
2020/02/24 Python
python实现定时发送邮件到指定邮箱
2020/12/23 Python
PyQt5中QSpinBox计数器的实现
2021/01/18 Python
英国领先的大码时装品牌之一:Elvi
2018/08/26 全球购物
医科大学生的自我评价
2013/12/04 职场文书
小学毕业感言50字
2014/02/16 职场文书
服装设计师职业生涯规划范文
2014/02/28 职场文书
周年庆促销方案
2014/03/15 职场文书
银行业务授权委托书
2014/10/10 职场文书
党员干部反四风民主生活会对照检查材料思想汇报
2014/10/12 职场文书
2015年音乐教师个人工作总结
2015/05/20 职场文书
高端收音机+蓝牙音箱,JBL TUNER FM带收音蓝牙音箱评测
2021/04/24 无线电
python实现的web监控系统
2021/04/27 Python
Django实现在线无水印抖音视频下载(附源码及地址)
2021/05/06 Python
vue-cil之axios的二次封装与proxy反向代理使用说明
2022/04/07 Vue.js