触摸事件是移动浏览器特有的HTML5事件,虽然click事件在pc和移动端更通用,但是在移动端会出现300ms延迟,较为影响用户体验,300ms延迟来自判断双击和长按,因为只有默认等待时间结束以确定没有后续动作发生时,才会触发click事件。所以触摸事件反应更快,体验更好。
触摸事件的类型:
为了区别触摸相关的状态改变,存在多种类型的触摸事件。可以通过检查触摸事件的 TouchEvent.type
属性来确定当前事件属于哪种类型。
注意: 在很多情况下,触摸事件和鼠标事件会同时被触发(目的是让没有对触摸设备优化的代码仍然可以在触摸设备上正常工作)。如果你使用了触摸事件,可以调用 event.preventDefault()
来阻止鼠标事件被触发。
标准的触摸事件
事件名称 | 描述 | 包含touches数组 |
touchstart |
当用户在触摸平面上放置了一个触点时触发。事件的目标 element 将是触点位置上的那个目标 element |
是 |
touchmove |
当用户在触摸平面上移动触点时触发。 事件的目标 哪怕当 |
是 |
touchend |
当一个触点被用户从触摸平面上移除(当用户将一个手指离开触摸平面)时触发。 当触点移出触摸平面的边界时也将触发。例如用户将手指划出屏幕边缘。 已经被从触摸平面上移除的触点,可以在 |
是 |
touchenter |
当触点进入某个 element 时触发。此事件没有冒泡过程。 |
是 |
touchleave |
当触点离开某个 element 时触发。此事件没有冒泡过程。 |
是 |
touchcancel |
当触点由于某些原因被中断时触发。有几种可能的原因如下(具体的原因根据不同的设备和浏览器有所不同):
|
是 |
触摸对象属性
Touch.identifier |
返回一个可以唯一地识别和触摸平面接触的点的值. 这个值在这根手指(或触摸笔等)所引发的所有事件中保持一致, 直到它离开触摸平面. |
Touch.screenX |
触点相对于屏幕左边沿的的X坐标. 只读属性. |
Touch.screenY |
触点相对于屏幕上边沿的的Y坐标. 只读属性. |
Touch.clientX |
触点相对于可见视区左边沿的的X坐标. 不包括任何滚动偏移. 只读属性. |
Touch.clientY |
触点相对于可见视区上边沿的的Y坐标. 不包括任何滚动偏移. 只读属性. |
Touch.pageX |
触点相对于HTML文档左边沿的的X坐标. 当存在水平 滚动的 偏移时, 这个值包含了水平滚动的偏移 . 只读属性. |
Touch.pageY |
触点相对于HTML文档上边沿的的Y坐标. 当存在水平滚动的偏移时, 这个值包含了垂直滚动的偏移 . 只读属性. |
Touch.radiusX |
能够包围用户和触摸平面的接触面的最小椭圆的水平轴(X轴)半径. 这个值的单位和 screenX 相同. 只读属性. |
Touch.force |
手指挤压触摸平面的压力大小, 从0.0(没有压力)到1.0(最大压力)的浮点数. 只读属性. |
Touch.radiusY |
能够包围用户和触摸平面的接触面的最小椭圆的垂直轴(Y轴)半径. 这个值的单位和 screenY 相同. 只读属性. |
Touch.target |
当这个触点最开始被跟踪时(在 或者这个元素已经被从文档中移除. 需要注意的是, 如果这个元素在触摸过程中被移除, 这个事件仍然会指向它, 但是不会再冒泡这个事件到 因此, 如果有元素在触摸过程中可能被移除, 最佳实践是将触摸事件的监听器绑定到这个元素本身, 防止元素被移除后, 无法再从它的上一级元素上侦测到从该元素冒泡的事件. 只读属性. |
IE10+的触摸事件
事件名称 | 描述(在触摸设备上) |
---|---|
MSPointerDown | 触摸开始 |
MSPointerMove | 接触点移动 |
MSPointerUp | 触摸结束 |
MSPointerOver | 触摸点移动到元素内,相当于mouseover |
MSPointerOut | 触摸点离开元素,相当于mouseout |
MSPointerEvent属性
属性 | 描述 |
---|---|
hwTimestamp | 创建事件的时间(ms) |
isPrimary | 标识该指针是不是主指针 |
pointerId | 指针的唯一ID(类似于触摸事件的标识符) |
pointerType | 一个整数,标识了该事件来自鼠标、手写笔还是手指 |
pressure | 笔的压力,0-255,只有手写笔输入时才可用 |
rotation | 0-359的整数,光标的旋转度(如果支持的话) |
tiltX/tiltY | 手写笔的倾斜度,只有用手写笔输入时才支持 |
等价事件
鼠标 | 触摸 | 键盘 |
mousedown | touchstart | keydown |
mousemove | touchmove | keydown |
mouseup | touchend | keyup |
mouseover | focus |
很显然,触摸动作序列:touchstart-touchmove-touchend和鼠标序 列:mousedown-mousemove-mouseup以及键盘序列:keydown-keypress-keyup很相似,这并不是巧合,因为这 三种交互模式都可以描述为start-move-stop。
话说回来,click要经过touchstart-touchmove-touchend流程,300ms延迟,所以需要tap事件,tap就是在同一个点轻触时间很短。
封装好的tap和longtap事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
( function () { var TOUCHSTART, TOUCHEND; if ( typeof (window.ontouchstart) != 'undefined' ) { TOUCHSTART = 'touchstart' ; TOUCHEND = 'touchend' ; TOUCHMOVE= 'touchmove' ; } else if ( typeof (window.onmspointerdown) != 'undefined' ) { TOUCHSTART = 'MSPointerDown' ; TOUCHEND = 'MSPointerUp' ; TOUCHMOVE= 'MSPointerMove' ; } else { TOUCHSTART = 'mousedown' ; TOUCHEND = 'mouseup' ; TOUCHMOVE = 'mousemove' ; } function NodeTouch(node) { this ._node = node; } function tap(node,callback,scope) { node.addEventListener(TOUCHSTART, function (e) { x = e.touches[0].pageX; y = e.touches[0].pageY; }); node.addEventListener(TOUCHEND, function (e) { e.stopPropagation(); e.preventDefault(); var curx = e.changedTouches[0].pageX; var cury = e.changedTouches[0].pageY; if (Math.abs(curx - x) < 6 && Math.abs(cury - y) < 6) { callback.apply(scope, arguments); } }); } function longTap(node,callback,scope) { var x,y,startTime=0,endTime=0,in_dis= false ; node.addEventListener(TOUCHSTART, function (e) { x = e.touches[0].pageX; y = e.touches[0].pageY; startTime=( new Date()).getTime(); }); node.addEventListener(TOUCHEND, function (e) { e.stopPropagation(); e.preventDefault(); var curx = e.changedTouches[0].pageX; var cury = e.changedTouches[0].pageY; if (Math.abs(curx - x) < 6 && Math.abs(cury - y) < 6) { in_dis= true ; } else { in_dis= false ; } endTime=( new Date()).getTime(); if (endTime - startTime > 300 && in_dis) { callback.apply(scope, arguments); } }); } NodeTouch.prototype.on = function (evt, callback, scope) { var scopeObj; var x,y; if (!scope) { scopeObj = this ._node; } else { scopeObj = scope; } if (evt === 'tap' ) { tap( this ._node,callback,scope); } else if (evt === 'longtap' ){ longTap( this ._node,callback,scope); } else { this ._node.addEventListener(evt, function () { callback.apply(scope, arguments); }); } return this ; } window.$ = function (selector) { var node = document.querySelector(selector); if (node) { return new NodeTouch(node); } else { return null ; } } })(); var box=$( "#box" ); box.on( "longtap" , function (){ console.log( "你已经长按了" ); },box) |