移动端的touch事件(一)

移动端的应用现在占据着越来越大的比重,所以对于前端开发人员来说,就不得不去学习移动端开发的技能,相对于PC端,移动端有更炫的界面展示,并且可以随意的使用各种PC端不能随意使用的东西,比如HTML5CSS3,虽然移动端的开发的开发现在智能手机,大屏幕的移动设备,越来越普及,也就导致了移动端一些

touch对象

移动端的touch事件的基础就是基于touch对象的,每一个touch对象,都包含了一些基本的信息,来记录该对象的详细信息,而我们在后面进行的处理,就是在对这些信息的收集,分析,响应,处理的过程。

那么,touch对象,具体包含哪些属性和方法呢?

属性 意义
identifier Touch 对象的唯一标识符. 一次触摸动作(我们指的是手指的触摸)在平面上移动的整个过程中, 该标识符不变. 可以根据它来判断跟踪的是否是同一次触摸过程. 只读属性.
screenX 触点相对于屏幕左边沿的的X坐标. 只读属性.
screenY 触点相对于屏幕上边沿的的Y坐标. 只读属性.
clientX 触点相对于可见视区(visual viewport)左边沿的的X坐标. 不包括任何滚动偏移. 只读属性.
clientY 触点相对于可见视区(visual viewport)上边沿的的Y坐标. 不包括任何滚动偏移. 只读属性.
clientX 触点相对于可见视区(visual viewport)左边沿的的X坐标. 不包括任何滚动偏移. 只读属性.
pageX 触点相对于HTML文档左边沿的的X坐标. 当存在水平滚动的偏移时, 这个值包含了水平滚动的偏移. 只读属性.
pageY 触点相对于HTML文档上边沿的的Y坐标. 当存在水平滚动的偏移时, 这个值包含了垂直滚动的偏移. 只读属性.
radiusX 能够包围用户和触摸平面的接触面的最小椭圆的水平轴(X轴)半径. 这个值的单位和 screenX 相同. 只读属性.
radiusY 能够包围用户和触摸平面的接触面的最小椭圆的垂直轴(Y轴)半径. 这个值的单位和 screenY 相同. 只读属性.
rotationAngle 它是这样一个角度值:由radiusX 和 radiusY 描述的正方向的椭圆,需要通过顺时针旋转这个角度值,才能最精确地覆盖住用户和触摸平面的接触面. 只读属性.
force 手指挤压触摸平面的压力大小, 从0.0(没有压力)到1.0(最大压力)的浮点数. 只读属性.
target 当这个触点最开始被跟踪时(在 touchstart 事件中), 触点位于的HTML元素. 哪怕在触点移动过程中, 触点的位置已经离开了这个元素的有效交互区域, 或者这个元素已经被从文档中移除. 需要注意的是, 如果这个元素在触摸过程中被移除, 这个事件仍然会指向它, 但是不会再冒泡这个事件到 window 或 document 对象. 因此, 如果有元素在触摸过程中可能被移除, 最佳实践是将触摸事件的监听器绑定到这个元素本身, 防止元素被移除后, 无法再从它的上一级元素上侦测到从该元素冒泡的事件. 只读属性.

上述这些,都是touch对象比较基本的一些信息,同时touch事件还有一些事件响应,这个后面继续说。

如果想要看看touch对象有哪些具体的属性,可以再移动端点击下面这个链接,并用手指进行触摸操作,touch对象的属性

事件类型

touch对象上的属性是很多的,如果您有耐心的把上一个链接使用手机浏览器打开,并执行了触摸操作,你会看到很多上一小节的列表中,不包含的属性,就比如,我们这里想要说的事件类型属性,事件类型的属性是保存在TouchEvent.type的标签中的。

注意: 在很多情况下,触摸事件和鼠标事件会同时被触发(目的是让没有对触摸设备优化的代码仍然可以在触摸设备上正常工作)。如果你使用了触摸事件,可以调用 event.preventDefault() 来阻止鼠标事件被触发。

TouchEvent.type的值,理论上包含以下几种:

事件类型 意义
touchstart 当用户在触摸平面上放置了一个触点时触发,类似于click事件中的mouseDown事件。当手指接触触摸屏时被触发
touchend 当一个触点被用户从触摸平面上移除(当用户将一个手指离开触摸平面)时触发。当触点移出触摸平面的边界时也将触发。事件的目标 element 和这个 touchend 事件对应的 touchstart 事件的目标 element 相同,哪怕 touchend 事件触发时,触点已经移出了该 element 。
touchmove 当用户在触摸平面上移动触点时触发。事件的目标 element 和这个 touchend 事件对应的 touchstart 事件的目标 element 相同,哪怕当 touchend 事件触发时,触点已经移出了该 element 。当触点的半径、旋转角度以及压力大小发生变化时,也将触发此事件。注意: 不同浏览器上 touchmove 事件的触发频率并不相同。这个触发频率还和硬件设备的性能有关。因此决不能让程序的运作依赖于某个特定的触发频率
touchenter 当触点进入某个 element 时触发。注意: 此事件没有冒泡过程。
touchleave 当触点离开某个 element 时触发。注意: 此事件没有冒泡过程。
touchcancel 当触点由于某些原因被中断时触发。有几种可能的原因如下(具体的原因根据不同的设备和浏览器有所不同):1,由于某个事件取消了触摸:例如触摸过程被一个模态的弹出框打断。2,触点离开了文档窗口,而进入了浏览器的界面元素、插件或者其他外部内容区域。3,当用户产生的触点个数超过了设备支持的个数,从而导致 TouchList 中最早的 Touch 对象被取消。

在我现在的感觉中,我们常用的只有两种属性,那就是touchstarttouchend事件。touchmove事件我也觉得是很不错的,只是IOS的有些版本下,只有在touchstart事件的时候,才会触发一次touchmove,然后在touchend之前,都不会再继续触发touchmove事件,所以,觉得这个事件有点鸡肋,并没有什么实际的用途。

并且,不管touchstarttouchend事件,都是touch事件的一部分,而touch事件在没有执行结束之前,是无法执行其他的事件的,说白了,就是JS是一个单线程的语言,而touch事件是一个动作,在touch事件没有志向完成之前,是不能执行其他的动作的,包括事件计时器等,看下面的这个例子:

代码以及结构都是很简单的,如下:


<body>
<div>
	<h1>touchStart event</h1>
	<div id = "touchStart"></div>
</div>
<div>
	<h1>touchEnd event</h1>
	<div id = "touchEnd"></div>
</div>
<div style = "color:#f00;margin-bottom:20px;">
	计时器:<span id = "timeInter">0</span>
</div>
<div style = "height:100px;">test</div>
<div style = "height:100px;">test</div>
<div style = "height:100px;">test</div>
<div style = "height:100px;">test</div>
<div style = "height:100px;">test</div>
<script type="text/javascript">
function $(id){
    return document.getElementById(id);
}

var i = 0;
setInterval(function (){
    $("timeInter").innerHTML = ++i;
},1000);
</script>
</body>


这个页面对于前端开发来说应该是一个很常见的,也算是很基础的一个功能了,那就是计时器,但是当移动端来临,touch事件的出现,这个计时器就不再那么完美了,因为想想计时器的工作原理,每隔一定的时间,把一个需要调用的函数,推入到事件队列中,但是当alert,这样的阻塞事件发生时,就会影响计时器的工作,也有一种情况就是,某一段JS执行需要很长的时间,也会影响,而touch事件的触发,就是这样,比如像上面的这个简单的例子,如果你的手指在页面上一直处于滑动状态,就是抱着touch事件一直处于触发状态,那么整个页面就会被阻塞,无法执行其他的所有的JS代码。

移动端查看示例地址:touch事件影响计时器,

这里,你也许会想到之前刚刚提到的一个touch事件的类型,touchmove事件,是不是我们可以再touchmove事件内部进行处理呢?

关于touchmove事件的问题,之前也有提到过了,不知道您是否还记得,就是touchmove事件,在有些系统上(IOSAndroid都有吧,不能保证是否所有的系统都是这样),touchmove事件,只和touchstart同时被触发,而在之后,touchend之前,是不会再次被触发的,也就是说,在每一次的touch事件的过程中,只会触发一次touchmove事件,那么这个事件又有什么用处呢?

关于tocuhmove事件只被触发一次的示例,可以移动端查看下面的这个链接:验证touchmove事件只执行一次

在我自己的Android设备上,以及之前在IOS下见过的一些情况,得出的是上述的结果,也许有的系统是支持的。

OK,这里关于touch事件的一些基础,先写到这里。

小结

关于touch事件会阻塞的问题,想想也是很容易理解的,毕竟JS是单线程的编程语言,而所有我们平时由于一些计算耗时过长,或者逻辑复杂,或者数据量大导致的页面假死的状态,都会影响整个页面的流畅性,因为他们都是一致在执行着JS代码,没有结束,所以导致其他代码无法执行。

而这里的touch事件,也是相同的原因,毕竟touch属于一个事件,而在这个事件没有执行结束之前,那么JS一直就是在执行着这个问题,而其他事件,都会因为touch事件的正在执行,而一直在事件流中处于排队状态。所以,可以理解,但是,touch事件的存在,就让计时器做时间判断时,在移动端就出了问题了。这个要在以后的移动端开发方面,多多注意了。

OK,本文暂且说到这里,如有疑问,请指正。

本文地址:http://www.zhangyunling.com/?p=223

yunling_zhang进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

移动端的touch事件(一)》有2个想法

  1. 匿名说道:

    touchmove事件在你滑动过程中会执行好多次的好么

    1. 我的测试情况时这样的,如果你在代码中,直接使用的touchmove事件,而没有做其他的处理,那么这个touchmove是只执行一次的,这个您可以直接查看文中的示例,查看源代码以及在手机上测试,而touchmove多次触发的情况,是如果您在touchmove的处理回调中,阻止了该事件的默认动作,那么在滑动的过程中,会一直触发该事件的,同时,在该事件的回调中,也一直可以被处理,可以参考:移动端的touch事件(二),或者您可以直接查看那篇文章中的一个示例:touchmove一直被触发的示例。而且在一些自定义的滑动插件中,都是在touchmove的回调中,阻止了它的默认动作,来实现一直触发touchmove事件的。

      比如常用的滑动插件iscroll中,它在捕获touchmove事件时,就在其回调函数中“_move”方法中,都使用了阻止默认动作的处理,可以查看源码:iscroll,直接搜索“_move”方法即可。

      如果我这里的说法有什么问题,也请指出,谢谢!