触摸事件中touchstar、touchmove、touchend、touchcancel事件应用方法及实例
iOS版 Safari为了向开发人员传达一些特殊信息,新增了一些专有事件。因为 iOS设备既没有鼠标 也没有键盘,所以在为移动 Safari开发交互性网页时,常规的鼠标和键盘事件根本不够用。随着 Android 中的 WebKit 的加入,很多这样的专有事件变成了事实标准,导致 W3C开始制定 Touch Events规范(参 见 https://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html)。以下介绍的事件只针对触摸设备。
触摸事件包含 iOS 2.0软件的 iPhone 3G发布时,也包含了一个新版本的 Safari浏览器。这款新的移动 Safari 提供了一些与触摸(touch)操作相关的新事件。后来,Android上的浏览器也实现了相同的事件。触摸 事件会在用户手指放在屏幕上面时、在屏幕上滑动时或从屏幕上移开时触发。具体来说,有以下几个触 摸事件。
touchstart:当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。
touchmove:当手指在屏幕上滑动时连续地触发。在这个事件发生期间,调用preventDefault() 可以阻止滚动。
touchend:当手指从屏幕上移开时触发。
touchcancel:当系统停止跟踪触摸时触发。关于此事件的确切触发时间,文档中没有明确说明。
上面这几个事件都会冒泡,也都可以取消。虽然这些触摸事件没有在 DOM规范中定义,但它们却 是以兼容 DOM的方式实现的。因此,每个触摸事件的 event 对象都提供了在鼠标事件中常见的属性: bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、 ctrlKey 和 metaKey。
除了常见的 DOM属性外,触摸事件还包含下列三个用于跟踪触摸的属性。
touches:表示当前跟踪的触摸操作的 Touch 对象的数组。
targetTouchs:特定于事件目标的 Touch 对象的数组。
changeTouches:表示自上次触摸以来发生了什么改变的 Touch 对象的数组。 每个 Touch 对象包含下列属性。
clientX:触摸目标在视口中的 x坐标。
clientY:触摸目标在视口中的 y坐标。
identifier:标识触摸的唯一 ID。
pageX:触摸目标在页面中的 x坐标。
pageY:触摸目标在页面中的 y坐标。
screenX:触摸目标在屏幕中的 x坐标。
screenY:触摸目标在屏幕中的 y坐标。
target:触摸的 DOM节点目标。 使用这些属性可以跟踪用户对屏幕的触摸操作。来看下面的例子。
<!DOCTYPE html>
<html>
<head>
<title>Touch Events Example</title>
<meta name="viewport" content="width=device-width, user-scalable=no">
</head>
<body>
<p>Touch anywhere on the screen. This only works on an iPhone or iPod Touch running iPhone 2.x software.</p>
<div id="output">
</div>
<script type="text/javascript">
function handleTouchEvent(event){
//只跟踪一次触摸
if (event.touches.length == 1){
var output = document.getElementById("output");
switch(event.type){
case "touchstart":
output.innerHTML = "Touch started (" + event.touches[0].clientX + "," + event.touches[0].clientY + ")";
break;
case "touchend":
output.innerHTML += "<br>Touch ended (" + event.changedTouches[0].clientX + "," + event.changedTouches[0].clientY + ")";
break;
case "touchmove":
event.preventDefault(); //prevent scrolling
output.innerHTML += "<br>Touch moved (" + event.changedTouches[0].clientX + "," + event.changedTouches[0].clientY + ")";
break;
}
}
}
document.addEventListener("touchstart", handleTouchEvent, false);
document.addEventListener("touchend", handleTouchEvent, false);
document.addEventListener("touchmove", handleTouchEvent, false);
</script>
</body>
</html>
以上代码会跟踪屏幕上发生的一次触摸操作。为简单起见,只会在有一次活动触摸操作的情况下输 出信息。当 touchstart 事件发生时,会将触摸的位置信息输出到<div>元素中。当 touchmove 事件 发生时,会取消其默认行为,阻止滚动(触摸移动的默认行为是滚动页面),然后输出触摸操作的变化 信息。而 touchend 事件则会输出有关触摸操作的终信息。注意,在 touchend 事件发生时,touches 集合中就没有任何 Touch 对象了,因为不存在活动的触摸操作;此时,就必须转而使用 changeTouchs 集合。
这些事件会在文档的所有元素上面触发,因而可以分别操作页面的不同部分。在触摸屏幕上的元素 时,这些事件(包括鼠标事件)发生的顺序如下:
(1)touchstart
(2) mouseover
(3) mousemove(一次)
(4) mousedown
(5) mouseup
(6) click
(7) touchend
支持触摸事件的浏览器包括 iOS版 Safari、Android版 WebKit、bada版 Dolfin、OS6+中的 BlackBerry WebKit、Opera Mobile 10.1+和 LG专有 OS中的 Phantom浏览器。目前只有 iOS版 Safari支持多点触摸。 桌面版 Firefox 6+和 Chrome也支持触摸事件。
以下是四种touch事件
touchstart: //手指放到屏幕上时触发
touchmove: //手指在屏幕上滑动式触发
touchend: //手指离开屏幕时触发
touchcancel: //系统取消touch事件的时候触发,这个好像比较少用
每个触摸事件被触发后,会生成一个event对象,event对象里额外包括以下三个触摸列表
touches: //当前屏幕上所有手指的列表
targetTouches: //当前dom元素上手指的列表,尽量使用这个代替touches
changedTouches: //涉及当前事件的手指的列表,尽量使用这个代替touches
这些列表里的每次触摸由touch对象组成,touch对象里包含着触摸信息,主要属性如下:
clientX / clientY: //触摸点相对浏览器窗口的位置
pageX / pageY: //触摸点相对于页面的位置
screenX / screenY: //触摸点相对于屏幕的位置
identifier: //touch对象的ID
target: //当前的DOM元素
注意:
手指在滑动整个屏幕时,会影响浏览器的行为,比如滚动和缩放。所以在调用touch事件时,要注意禁止缩放和滚动。
1.禁止缩放
通过meta元标签来设置。
<meta name="viewport" content="target-densitydpi=320,width=640,user-scalable=no">
2.禁止滚动
preventDefault是阻止默认行为,touch事件的默认行为就是滚动。
event.preventDefault();
案例:
下面给出一个案例,需在移动设备上才能看出效果。
1.定义touchstart的事件处理函数,并绑定事件:
if(!!self.touch) self.slider.addEventListener('touchstart',self.events,false);
//定义touchstart的事件处理函数
start:function(event){
var touch = event.targetTouches[0]; //touches数组对象获得屏幕上所有的touch,取第一个touch
startPos = {x:touch.pageX,y:touch.pageY,time:+new Date}; //取第一个touch的坐标值
isScrolling = 0; //这个参数判断是垂直滚动还是水平滚动
this.slider.addEventListener('touchmove',this,false);
this.slider.addEventListener('touchend',this,false);
},
触发touchstart事件后,会产生一个event对象,event对象里包括触摸列表,获得屏幕上的第一个touch,并记下其pageX,pageY的坐标。定义一个变量标记滚动的方向。此时绑定touchmove,touchend事件。
2.定义手指在屏幕上移动的事件,定义touchmove函数。
//移动
move:function(event){
//当屏幕有多个touch或者页面被缩放过,就不执行move操作
if(event.targetTouches.length > 1 || event.scale && event.scale !== 1) return;
var touch = event.targetTouches[0];
endPos = {x:touch.pageX - startPos.x,y:touch.pageY - startPos.y};
isScrolling = Math.abs(endPos.x) < Math.abs(endPos.y) ? 1:0; //isScrolling为1时,表示纵向滑动,0为横向滑动
if(isScrolling === 0){
event.preventDefault(); //阻止触摸事件的默认行为,即阻止滚屏
this.slider.className = 'cnt';
this.slider.style.left = -this.index*600 + endPos.x + 'px';
}
},
同样首先阻止页面的滚屏行为,touchmove触发后,会生成一个event对象,在event对象中获取touches触屏列表,取得第一个touch,并记下pageX,pageY的坐标,算出差值,得出手指滑动的偏移量,使当前DOM元素滑动。
3.定义手指从屏幕上拿起的事件,定义touchend函数。
//滑动释放
end:function(event){
var duration = +new Date - startPos.time; //滑动的持续时间
if(isScrolling === 0){ //当为水平滚动时
this.icon[this.index].className = '';
if(Number(duration) > 10){
//判断是左移还是右移,当偏移量大于10时执行
if(endPos.x > 10){
if(this.index !== 0) this.index -= 1;
}else if(endPos.x < -10){
if(this.index !== this.icon.length-1) this.index += 1;
}
}
this.icon[this.index].className = 'curr';
this.slider.className = 'cnt f-anim';
this.slider.style.left = -this.index*600 + 'px';
}
//解绑事件
this.slider.removeEventListener('touchmove',this,false);
this.slider.removeEventListener('touchend',this,false);
},
手指离开屏幕后,所执行的函数。这里先判断手指停留屏幕上的时间,如果时间太短,则不执行该函数。再判断手指是左滑动还是右滑动,分别执行不同的操作。最后很重要的一点是移除touchmove,touchend绑定事件。