移动互联网终端的touch事件,touchstart, touchend, touchmove
诸如智能手机和平板电脑一类的移动设备通常会有一个电容式触摸屏(capacitive touch-sensitive screen),以捕捉用户的手指所做的交互。随着移动网络的发展,其能够支持越来越复杂的应用,web开发者需要一种方法来处理这些事件。例如,几乎所 有的快节奏游戏都需要玩家一次按下多个按钮,这种方式,在触摸屏情况下,意味着多点触摸。Apple在iOS 2.0中引入了触摸事件API,Android正迎头赶上这一事实标准,缩小差距。最近一个W3C工作组正合力制定这一触摸事件规范。
iOS上的Safari也支持click 和mouseover等传统的交互事件,只是不推荐在iOS的浏览器应用上使用click和mouseover,因为这两个事件是为了支持鼠标点击而设计 出来的。Click事件在iOS上会有半秒左右的延迟,原因是iOS要highlight接收到click的element。而 mouseover/out等事件则会被手指的点击触发。所以,在iOS上,应当抛弃传统的交互事件模型而接受一个新的事件模型。Touch事件和更高级 的Gesture事件,能让你的网页交互起来像native应用一样。
三种在规范中列出并获得跨移动设备广泛实现的基本触摸事件:
1. touchstart :手指放在一个DOM元素上。
2. touchmove :手指拖曳一个DOM元素。
3. touchend :手指从一个DOM元素上移开。
每个触摸事件都包括了三个触摸列表:
1. touches :当前位于屏幕上的所有手指的一个列表。
2. targetTouches :位于当前DOM元素上的手指的一个列表。
3. changedTouches :涉及当前事件的手指的一个列表。
例如,在一个touchend事件中,这就会是移开的手指。
这些列表由包含了触摸信息的对象组成:
1. identifier :一个数值,唯一标识触摸会话(touch session)中的当前手指。
2. target :DOM元素,是动作所针对的目标。
3. 客户/页面/屏幕坐标 :动作在屏幕上发生的位置。
4. 半径坐标和 rotationAngle :画出大约相当于手指形状的椭圆形。
在开始描述touch事件之前,需要先描述一下多触式系统中特有的touch对象(android和iOS乃至nokia最新的meego系统都模拟了类 似的对象,这里只针对iOS,因为我只有iPad可用于测试。。)。这个对象封装一次屏幕触摸,一般来自于手指。它在touch事件触发的时候产生,可以 通过touch event handler的event对象取到(一般是通过event.changedTouches属性)。这个对象包括一些重要的属性:
client / clientY:触摸点相对于浏览器窗口viewport的位置
pageX / pageY:触摸点相对于页面的位置
screenX /screenY:触摸点相对于屏幕的位置
identifier: touch对象的unique ID
我们从一个单根手指触摸的实例开始进入多触式网页的世界。当一根手指放下的时候,屏幕上出现一个方块,手指移动方块也随着移动,手指提起方块消失。首先,让我们定义一下方块的css:
*{margin:0;padding:0}
html,body{height:100%}
.spirit{position:absolute;width:50px;height:50px;background-color:red;}
#canvas{position:relative;width:100%;height:200px;background-color:#ccc}
然后,在body下定义一个接收事件的容器:
<div id="canvas"></div>
定义touchstart的事件处理函数,并绑定事件:
var canvas = document.getElementById("canvas"), spirit, startX, startY; function touchStart(event) { //阻止网页默认动作(即网页滚动) event.preventDefault(); if (spirit || !event.touches.length) return; var touch = event.touches[0]; startX = touch.pageX; startY = touch.pageY; spirit = document.createElement("div"); canvas.appendChild(spirit); spirit.className = "spirit"; spirit.style.left = startX + "px"; spirit.style.top = startY + "px"; } canvas.addEventListener("touchstart", touchStart, false);
首先,我们将方块spirit作为一个全局对象,因为我们现在要测试单根手指所以屏幕上最好只有一个物体在移动(等会有多触实例)。在touchStart这个事件处理函数中,我们也首先判断了是否已经产生了spirit,也就是是否已经有一个手指放到屏幕上,如果是,直接返回。
和传统的event listener一样,多触式系统也会产生一个event对象,只不过这个对象要多出一些属性,比如这里的event.touches,这个数组对象获得屏幕上所有的touch。注意这里的event.preventDefault(),在传统的事件处理函数中,这个方法阻止事件的默认动作,触摸事件的默认动作是滚屏,我们不想屏幕动来动去的,所以先调用一下这个函数。我们取第一个touch,将其pageX/Y作为spirit创建时的初始位置。接下来,我们创建一个div,并且设置className,left,top三个属性。最后,我们把spirit对象appendChild到容器中。这样,当第一根手指放下的时候,一个红色的,50px见方的方块就放到屏幕上了。
然后,我们要开始处理手指在屏幕上移动的事件:
function touchMove(event) {
event.preventDefault();
if (!spirit || !event.touches.length) return;
var touch = event.touches[0],
x = touch.pageX - startX,
y = touch.pageY - startY;
//这里是为了手指一定是横向滚动的,原理是计算X位置的偏移要比Y的偏移大
if (Math.abs(x) > Math.abs(y)) {
spirit.style.left = touch.pageX + "px";
spirit.style.top = touch.pageY + "px";
}
}
canvas.addEventListener("touchmove", touchMove, false);
在touch move listener中,我们使用webkit特有的css属性:webkitTransform来移动方块,这个属性具体怎么用请google之。建议构造面向iOS设备的网页的时候尽量使用webkit自己的特性,不但炫,更可以直接利用硬件来提高性能。
最后,我们处理touchend事件。手指提起的时候方块从屏幕上移除。
function touchEnd(event) { if (!spirit) return; canvas.removeChild(spirit); spirit = null; } canvas.addEventListener("touchend", touchEnd, false);
在你的ipad或者iphone上测试一下以上代码。如果不出意外的话,一个完整的多触式web程序就诞生了。。
设备支持
遗憾的是,触摸事件的实现在完备性和质量方面的差别很大。我编写了一个诊断脚本来显示一些关于触摸API实现的基本信息,其中包括哪些事件是支持 的,以及 touchmove事件触发的解决方案。我在Nexus One和Nexus S硬件上测试了Android 2.3.3,在Xoom上测试了Android 3.0.1,以及在iPad和iPhone上测试了iOS 4.2。
简而言之,所有被测试的浏览器都支持touchstart、touchend和touchmove事件。
规范提供了额外的三个触摸事件,但被测试的浏览器没有支持它们:
1. touchenter :移动的手指进入一个DOM元素。
2. toucheleave :移动手指离开一个DOM元素。
3. touchcancel :触摸被中断(实现规范)。
被测试的浏览器还在每个触摸列表内部都提供了touches、targetTouches和changedTouches列表。不过,被测试的浏 览器没有支持 radiusX、radiusY或是rotationAngle属性,这些属性指明触摸屏幕的手指的形状。在一次touchmove期间,事件大约一秒钟 触发60次,所有的被测试设备都是这样。
<html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <script id="others_zepto_10rc1" type="text/javascript" class="library" src="http://sandbox.runjs.cn/js/sandbox/other/zepto.min.js"></script> </head> <body> <div id="d" style=" width: 100px; height: 100px; border: 1px solid black;"></div> <div id="d2" style=" width: 100px; height: 100px; border: 1px solid orange;"></div> <script type="text/javascript"> var startTime; var t = false, m = false; var log = function (msg) { var div = $('<div></div>'); div.html((new Date().getTime()) + ': ' + (new Date().getTime() - startTime) + ': ' + msg) $('body').append(div); }; var touchStart = function () { log('start'); startTime = new Date().getTime(); t = true; log('touchStart'); }; var touchEnd = function () { t = false; log('touchEnd'); }; var touchMove = function (e) { e.preventDefault(); if (!t) return false; log('touchMove'); }; var mouseDown = function (e) { e.preventDefault(); startTime = startTime || new Date().getTime(); m = true; log('mouseDown'); }; var mouseClick = function () { log('mouseClick'); }; var mouseUp = function () { m = false; log('mouseUp'); }; var mouseMove = function (e) { e.preventDefault(); if (!m) return; log('mousemove'); }; var d = $('#d'); var dd = $('#d2'); dd.bind('mousedown', mouseDown); dd.bind('click', mouseClick); dd.bind('mouseup', mouseUp); dd.bind('mousemove', mouseMove); d.bind('touchstart', touchStart); d.bind('touchend', touchEnd); d.bind('touchmove', touchMove); </script> <style></style> <script></script> <!-- Generated by RunJS (Fri Jul 03 09:54:14 CST 2015) 0ms --></body></html>
处理Touch事件能让你跟踪用户的每一根手指的位置。你可以绑定以下四种Touch事件:
一、
touchstart:// 手指放到屏幕上的时候触发
touchmove:// 手指在屏幕上移动的时候触发
touchend:// 手指从屏幕上拿起的时候触发
touchcancel:// 系统取消touch事件的时候触发。至于系统什么时候会取消,不详
二、
client / clientY:// 触摸点相对于浏览器窗口viewport的位置
pageX / pageY:// 触摸点相对于页面的位置
screenX /screenY:// 触摸点相对于屏幕的位置
identifier:>// touch对象的unique ID
三,
每个Touch对象包含下列属性。
clientX:触摸目标在视口中的X坐标。
clientY:触摸目标在视口中的Y坐标。
identifier:表示触摸的唯一ID。
pageX:触摸目标在页面中的x坐标。
pageY:触摸目标在页面中的y坐标。
screenX:触摸目标在屏幕中的x坐标。
screenY:触摸目标在屏幕中的y坐标。
target:触摸的DOM节点坐标。
<!doctype html> <html> <head> <meta charset="utf-8"> <title>touches</title> <style> body{ font-size:60px; color:red;} </style> <script> function touches(ev){ if(ev.touches.length==1){ var oDiv=document.getElementById('div1'); switch(ev.type){ case 'touchstart': oDiv.innerHTML='Touch start('+ev.touches[0].clientX+', '+ev.touches[0].clientY+')'; ev.preventDefault(); //阻止出现滚动条 break; case 'touchend': oDiv.innerHTML='Touch end('+ev.changedTouches[0].clientX+', '+ev.changedTouches[0].clientY+')'; break; case 'touchmove': oDiv.innerHTML='Touch move('+ev.changedTouches[0].clientX+', '+ev.changedTouches[0].clientY+')'; break; } } } document.addEventListener('touchstart',touches,false); document.addEventListener('touchend',touches,false); document.addEventListener('touchmove',touches,false); </script> </head> <body> <div id="div1"></div> </body> </html>
二、手势事件:
gesturestart: 当一个手指按在屏幕上,另一个手指有触发屏幕时,触发;
gestureend: 当你的任何一个手指从屏幕上移开的时候,触发;
gesturechange: 当触摸屏幕的任何一个手指发生变化的时候,触发;
在事件对象这里,其他的都还一样,在手势这里多了两个很有用的东西:
一个是rotation: 手指变化引起的旋转角度,顺时针为正的,逆时针为负的;
还有一个scale: 两个手指之间的距离变化;
<!doctype html> <html> <head> <meta charset="utf-8"> <title>gesture</title> <style> body{ font-size:60px; color:red;} </style> <script> window.onload=function(){ function gesture(ev){ var div=document.getElementById('div1'); switch(ev.type){ case 'gesturestart': div.innerHTML='Gesture start (rotation='+ev.rotation+', scale='+ev.scale+')'; ev.preventDefault(); break; case 'gestureend': div.innerHTML='Gesture End (rotation='+ev.rotation+', scale='+ev.scale+')'; break; case 'gesturechange': div.innerHTML='Gesture Change (rotation='+ev.rotation+', scale='+ev.scale+')'; break; } } document.addEventListener('gesturestart',gesture,false); document.addEventListener('gestureend',gesture,false); document.addEventListener('gesturechange',gesture,false); } </script> </head> <body> <div id="div1"></div> </body> </html>
现在jquery提供了一个非常不错的jquery手机插件,就是jquery mobile了,使用它就可以很方便哦。
摘自网络