如何实现swipe、tap、longTap等自定义事件

原创 我的小苹果 随笔 Zepto源码分析 300阅读 2018-03-04 00:40:04 举报

前言

移动端原生支持touchstarttouchmovetouchend等事件,但是在平常业务中我们经常需要使用swipetapdoubleTaplongTap等事件去实现想要的效果,对于这种自定义事件他们底层是如何实现的呢?让我们从Zepto.jstouch模块去分析其原理。您也可以直接查看touch.js源码注释

源码仓库

原文链接

touch

事件简述

Zepto的touch模块实现了很多与手势相关的自定义事件,分别是swipe, swipeLeft, swipeRight, swipeUp, swipeDown,doubleTap, tap, singleTap, longTap

事件名称事件描述
swipe滑动事件
swipeLeft←左滑事件
swipeRight→右滑事件
swipeUp↑上滑事件
swipeDown↓下滑事件
doubleTap双击事件
tap点击事件(非原生click事件)
singleTap单击事件
longTap长按事件

可以看到Zepto把这些方法都挂载到了原型上,这意味着,你可以直接用简写的方式例如$('body').tap(callback)

前置条件

在开始分析这些事件如何实现之前,我们先了解一些前置条件

  • 部分内部变量

touch: 用以存储手指操作的相关信息,例如手指按下时的位置,离开时的坐标等。

touchTimeout,tapTimeout, swipeTimeout,longTapTimeout分别存储singleTap、tap、swipe、longTap事件的定时器。

longTapDelay:longTap事件定时器延时时间

gesture: 存储ieGesture事件对象

  • 滑动方向判断(swipeDirection)

我们根据下图以及对应的代码来理解滑动的时候方向是如何判定的。需要注意的是浏览器中的“坐标系”和数学中的坐标系还是不太一样,Y轴有点反过来的意思。

手机屏幕坐标图

  • 触发长按事件

在触发长按事件之前先将longTapTimeout定时器取消,如果touch.last还存在则触发之,为什么要判断touch.last呢,因为swip, doubleTap,singleTap会将touch对象置空,当这些事件发生的时候,自然不应该发生长按事件。

  • 取消长按,以及取消所有事件

方式都是类似,先调用clearTimeout取消定时器,然后释放对应的变量,等候垃圾回收。

整体结构分析

这里将详细代码暂时省略了,留出整体框架,可以看出Zepto在dom,ready的时候在document上添加了MSGestureEnd,touchstart MSPointerDown pointerdown,touchmove MSPointerMove pointermove,touchcancel MSPointerCancel pointercancel等事件,最后还给在window上加了scroll事件。我们将目光聚焦在touchstart,touchmove,touchend对应的逻辑,其他相对少见的事件在暂不讨论

touchstart

要走到touchstart事件处理程序后续逻辑中,需要先满足一些条件。到底是哪些条件呢?先来看看isPointerEventType, isPrimaryTouch两个函数做了些什么。

**isPointerEventType

Pointer Event相关知识点击这里

isPrimaryTouch

根据mdn pointerType,其类型可以是mouse,pen,touch,这里只处理其值为touch并且isPrimary为true的情况。

接着回到

其实就是过滤掉非触摸事件。

触摸点信息兼容处理

这里只清楚e.touches[0]的处理逻辑,另一种不太明白,望有知晓的同学告知一下,感谢感谢。

复原终点坐标

存储触摸点部分信息

判断双击事件

处理长按事件

touchmove

手指移动的时候,做了三件事情。

  1. 取消长按事件
  2. 记录终点坐标
  3. 记录x轴和y轴的移动变化量

touchend

touchend事件触发时,相应的注释都在上面了,但是我们来分解一下这段代码。

swip事件相关

手指离开后,通过判断x轴或者y轴的位移,只要其中一个跨度大于30便会触发swip及其对应方向的事件。

tap,doubleTap,singleTap

这三个事件可能触发的前提条件是touch对象中还存在last属性,从touchstart事件处理程序中知道last在其中记录,而在touchend之前被清除的时机是长按事件被触发longTap,取消所有事件被调用cancelAll

只有当x轴和y轴的变化量都小于30的时候才会触发tap事件,注意在触发tap事件之前,Zepto还将往事件对象上添加了cancelTouch属性,对应的也就是cancelAll方法,即你可以通过他取消所有的touch相关事件。

在发生触发tap事件之后,如果是doubleTap,则会紧接着触发doubleTap事件,否则250毫秒之后触发singleTap事件,并且都会讲touch对象置为空对象,以便下次使用

touchcancel

touchcancel被触发的时候,取消所有的事件。

scroll

当滚动事件被触发的时候,取消所有的事件(这里有些不解,滚动事件触发,完全有可能是要触发tap或者swip等事件啊)。

结尾

最后说一个面试中经常会问的问题,touch击穿现象。如果对此有兴趣可以查看移动端click延迟及zepto的穿透现象, 新年第一发--深入不浅出zepto的Tap击穿问题

参考

  1. 移动端click延迟及zepto的穿透现象
  2. 新年第一发--深入不浅出zepto的Tap击穿问题
  3. 读Zepto源码之Touch模块
  4. pointerType
  5. [翻译]整合鼠标、触摸 和触控笔事件的Html5 Pointer Event Api

文章目录

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复