touchstart与click不得不说的故事

欢迎关注富途web开发团队 ,缺人从众css

有一次给公司作了个自适应的的费用介绍页,主要是关于收费标准的调整,老板表示很重视,适用人群也不少,因此也反馈获得几个不常遇到的问题,其中一个就是关于touchstartclick事件的问题。这里记录一下,欢迎指正。前端

1. 问题

某天中午,开发了好几天的费用介绍页终于上线了。运营同窗满怀信心地发送了收费标准页面的推广消息,而后咱们都潇洒地吃午餐去了。正吃着午餐的时候,收到微信群中某客户的反馈:咱们的页面最关键的地方——收费详情点击没有反应!android

页面点击无反应

随后咱们查看了前端错误上报和日志,没有任何线索。与客户确认环境,客户使用的是 windows PC 。web

但奇怪的是,我测试了多台设备,仍然没法重现问题。在同事的机器上也没能复现这个问题。windows

2. 溯源

咱们从新审视了一遍事件绑定的代码,发现其实很是简单。bash

var tap = 'ontouchstart' in window ? 'touchstart' : 'click';
wrap.addEvenListener(tap, function(){
    signUp();
});
复制代码

惟一有点特殊的就是咱们的页面是自适应的,为了不移动端点击 300ms 延迟,在绑定前作了一下判断,移动端绑定了touchstart事件,PC 端绑定了click事件。然而这段代码看起来也是人畜无害,并不至于致使点击没有反应。微信

3. 定位

咱们再次询问了客户更详细的环境信息,得到了一个很是关键的信息,客户使用的是联想的笔记本。因为在 surface 出来的时候组里有同事关注过,想起来当时联想也出了不少触屏笔记本。因而和客户再次联系,确认了他使用的就是联想的触屏笔记本。iphone

至此问题就很是明确了,问题最终仍是定位在绑定的“点击”事件上。咱们在检测时只是粗暴地检测了设备是否支持触控事件,却忽略了支持触控事件的仍然多是 PC 设备,客户仍然可能经过点击鼠标来进行操做。这实际上反映出咱们忽略了用户设备的多样性,开发的时候对用户设备作了太多的假设,最终致使咱们觉得它是一台手机,结果它是一台货真价实的笔记本电脑。函数

概括起来,关键的点就是:测试

  • 有些 PC 设备屏幕为触摸屏,同时支持touchstartclick事件;
  • 用户触发touchstart事件,默认必然会致使触发click事件,可是触发click事件,不必定会致使touchstart事件被触发;
  • 此类设备外接鼠标时,经过上面的绑定方式,会绑定touchstart事件,可是鼠标操做只能触发click,致使touchstart不触发;

4. 解决办法

至此,问题的缘由已经分析完毕,如何应对又成了一个问题。这个问题的关键在于肯定不一样设备上使用“点击”事件的策略。大体分为以下几种:

1. 均使用click事件

  • 优势:自适应时,不一样设备均支持,没有兼容性问题,开发成本低;
  • 缺点:移动端存在300ms的延迟问题(虽然同事表示通常感受不出来)

2. 经过UA判断设备是否为移动端,再确认事件类型

function isMobile() {
    return navigator.userAgent.match(/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i) ? true : false;
}
 var tap = isMobile() ? 'touchstart' : 'click';
复制代码
  • 优势:自适应时,开发成本低,经过设备类型肯定点击事件类型,能知足绝大部分问题,用户操做也比较符合预期;
  • 缺点:不能知足全部状况,若是用户给 iPad 或者 Android 手机(认定为移动设备)外接鼠标进行操做,这种方式就不起做用(PS:你非要这么作,我也无FUCK说)。

3. 所有使用click,经过FastClick解决300毫秒的延迟问题

//引入FastClick
var FastClick = require('tool-fastclick');
//页面初始化时调用
new FastClick(document.body);
复制代码
  • 优势:开发成本低也比较低,也不会出现1,2中问题
  • 缺点:额外引入三方库,FastClick 是否会有其余的坑?这点不能保证

注:tool-fastclick是组内 fork 的 FastClick 版本,目前没有开源。咱们对其中存在的问题进行了一部分修复,好比:同个页面有多个 select 框选择时,会跳选项的 bug 。

4. 万全之策

其实最好的方案是不要在绑定的时候进行判断,而是对touchstartclick同时绑定,可是在touchstart触发的时候暂时取消后续 click 的响应。

具体的实施方式有三种:

  1. touchstart事件响应中调用preventDefault()方法,阻止后续click事件的触发
  2. touchstart事件中设置一些标记,或者取消click事件的绑定,使得click事件触发时不会触发咱们绑定的逻辑,在一段时间(例如300-500ms)后再恢复
  3. 直接对事件处理函数进行节流(throttle),保证在一段时间内(300ms - 500ms),事件处理函数只触发一次

固然,和上面同样,每种方案都有利弊。

方案1取消了后续click事件的触发,在多个事件绑定叠加或者多人合做的时候,有可能致使一些依赖click事件的逻辑出现bug。

方案2和方案3的原理基本同样,实施起来有必定的复杂度,并且本质上属于 hack 的方案,应对一些很是规场景时就不适用了。好比须要快速连续点击的场景,或者用户点击很是慢的场景等等。

总之,没有万全之策,呵呵……

最后

有人可能会对文章最前提到的收费介绍页比较感兴趣,来了,看这里

相关文章
相关标签/搜索