通过一次报错详细谈谈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 相关文章推荐
默认让页面的第一个控件选中的javascript代码
Dec 26 Javascript
Js制作简单弹出层DIV在页面居中 中间显示遮罩的具体方法
Aug 08 Javascript
javascript 实现字符串反转的三种方法
Nov 23 Javascript
jQuery实现自动调整字体大小的方法
Jun 15 Javascript
jQuery动态背景图片效果实现方法
Jul 03 Javascript
JavaScript通过代码调用Flash显示的方法
Feb 02 Javascript
js Canvas实现圆形时钟教程
Sep 19 Javascript
详解微信小程序 template添加绑定事件
Jun 23 Javascript
基于BootStrap multiselect.js实现的下拉框联动效果
Jul 28 Javascript
jQuery实现弹窗下底部页面禁止滑动效果
Dec 19 jQuery
在 Vue 应用中使用 Netlify 表单功能的方法详解
Jun 03 Javascript
Vue 解决通过this.$refs来获取DOM或者组件报错问题
Jul 28 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
Linux下进行MYSQL编程时插入中文乱码的解决方案
2007/03/15 PHP
PHP OPCode缓存 APC详细介绍
2010/10/12 PHP
关于PHP中Object对象的笔记分享
2011/06/28 PHP
php后台多用户权限组思路与实现程序代码分享
2012/02/13 PHP
PHP的MVC模式实现原理分析(一相简单的MVC框架范例)
2014/04/29 PHP
列举PHP的Yii 2框架的开发优势
2015/07/03 PHP
基于ThinkPHP5.0实现图片上传插件
2017/09/25 PHP
PHP创建XML接口示例
2019/07/04 PHP
phpcmsv9.0任意文件上传漏洞解析
2020/10/20 PHP
关于this和self的使用说明
2010/08/01 Javascript
Three.js源码阅读笔记(Object3D类)
2012/12/27 Javascript
js点击出现悬浮窗效果不使用JQuery插件
2014/01/20 Javascript
JS实现统计复选框选中个数并提示确定与取消的方法
2015/07/01 Javascript
JS实现滑动菜单效果代码(包括Tab,选项卡,横向等效果)
2015/09/24 Javascript
JS获取月份最后天数、最大天数与某日周数的方法
2015/12/08 Javascript
原生JS封装ajax 传json,str,excel文件上传提交表单(推荐)
2016/06/21 Javascript
JS图片预加载插件详解
2017/06/21 Javascript
js array数组对象操作方法汇总
2019/03/18 Javascript
Seajs源码详解分析
2019/04/02 Javascript
微信小程序如何实现全局重新加载
2019/06/05 Javascript
vue使用map代替Aarry数组循环遍历的方法
2020/04/30 Javascript
40行代码把Vue3的响应式集成进React做状态管理
2020/05/20 Javascript
vue使用exif获取图片经纬度的示例代码
2020/12/11 Vue.js
Python操作列表之List.insert()方法的使用
2015/05/20 Python
解决python3爬虫无法显示中文的问题
2018/04/12 Python
Python递归调用实现数字累加的代码
2020/02/25 Python
新手学习Python2和Python3中print不同的用法
2020/06/09 Python
英国独特礼物想法和个性化礼物网站:notonthehighstreet.com
2018/04/16 全球购物
艺术应用与设计个人的自我评价
2013/11/23 职场文书
银行行长竞聘演讲稿
2014/04/23 职场文书
触电现场处置方案
2014/05/14 职场文书
舞蹈教育学专业自荐信
2014/06/15 职场文书
学校教师读书活动总结
2014/07/08 职场文书
教师个人年终总结
2015/02/11 职场文书
企业党建工作总结2015
2015/05/26 职场文书
MySQL中的布尔值,怎么存储false或true
2021/06/04 MySQL