iOS移动WEB开发之JS内置touch事件屏幕事件处理



iOS移动WEB开发之JS内置touch事件, OS系统的Safari也支持click 以及mouseover等传统的交互事件,不推荐在iOS浏览器应用上使用click和mouseover,主要是该事件是为支持鼠标点击而设计出来的。Click事件在iOS上有半秒延迟,因为iOS要highlight接收到click的element。而mouseover/out等事件则会被手指的点击触发。因此在iOS系统上上,应当抛弃传统的交互事件模型而接受一个新的事件模型。Touch事件一级更高级 的Gesture事件,会让网页交互起来像native应用一般。处理Touch事件可以让你跟踪用户的每一根手指的位置。你可以绑定以下四种Touch事件:

touchstart:  手指放到屏幕上的时候触发

touchmove:  手指在屏幕上移动的时候触发

touchend:  手指从屏幕上拿起的时候触发

touchcancel:  系统取消touch事件的时候触发。至于系统什么时候会取消,不详。。

   Gesture事件则是对touch事件的更高级的封装,主要处理手指slide、rotate、scale等动作,将在下一篇文章详述。

   在介绍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:
Javascript代码 

  1. .spirit              方块的class名称*/  
  2.   
  3.          position: absolute;  
  4.   
  5.          width: 50px;  
  6.   
  7.          height: 50px;  
  8.   
  9.          background-color: red;  
  10.   
  11.  

   接着在body下定义一个接收事件的容器,这里body的height必须是100%才能占满整个viewport:

Html代码 
  1. <body style=”height: 100%;margin:0;padding:0”>  
  2.   
  3. <div id=”canvas”  style=”position: relative;width:100%;height: 100%;”></div>  
  4.   
  5. </body>  

   定义touchstart的事件处理函数,并绑定事件:

Javascript代码 
  1. // define global variable  
  2.   
  3. var canvas document.getElementByIdx_x_x_x(“canvas”),  
  4.   
  5.        spirit, startX, startY;  
  6.   
  7. // touch start listener  
  8.   
  9. function touchStart(event)  
  10.   
  11.          event.preventDefault();  
  12.   
  13.          if (spirit ||! event.touches.length) return;  
  14.   
  15.          var touch event.touches[0];  
  16.   
  17.          startX touch.pageX;  
  18.   
  19.          startY touch.pageY;  
  20.   
  21.          spirit document_createElement_x_x_x(“div”);  
  22.   
  23.          spirit.className “spirit”;  
  24.   
  25.          spirit.style.left startX;  
  26.   
  27.          spirit.style.top startY;  
  28.   
  29.          canvas.a(spirit);  
  30.   
  31.  
  32.   
  33. // add touch start listener  
  34.   
  35. 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对象a到容器中。这样, 当第一根手指放下的时候,一个红色的,50px见方的方块就放到屏幕上了。

   然后,开始处理手指在屏幕上移动的事件:
Javascript代码 

  1. function touchMove(event)  
  2.   
  3.          event.preventDefault();  
  4.   
  5.          if (!spirit || !event.touches.length) return;  
  6.   
  7.          var touch event.touches[0],  
  8.   
  9.               touch.pageX – startX,  
  10.   
  11.                touch.pageY – startY;  
  12.   
  13.          spirit.style.webkitTransform ‘translate(‘ ‘px, ‘ ‘px)’;       
  14.   
  15.  
  16.   
  17. Canvas.addEventListener(“touchmove”, touchMove, false);  

   在touch move listener中,我们使用webkit特有的css属性:webkitTransform来移动方块,这个属性具体怎么用请google之。建议构造 面向iOS设备的网页的时候尽量使用webkit自己的特性,不但炫,更可以直接利用硬件来提高性能。

   最后,我们处理touchend事件。手指提起的时候方块从屏幕上移除。

Javascript代码 
  1. function touchEnd(event)  
  2.   
  3.          If (!spirit) return;  
  4.   
  5.          canvas.removeChild(spirit);  
  6.   
  7.          spirit null;  
  8.   
  9.  
  10.   
  11. canvas.addEventListener(“touchend”, touchEnd, false);  

在你的ipad或者iphone上测试一下以上代码。如果不出意外的话,一个完整的多触式web程序就诞生了。。

这种事件处理模式虽然能够满足我们开发多触式网页应用的需求,但是start – move – end的流程有点繁琐,能不能封装一些常用的动作让我们用一个event handler就能解决问题呢。没错,Gesture事件就是为了这个目的设计出来的,它封装了手指的scale, slide, rotate等常用的动作。不过,下一章我们再来讨论这个问题。。

附件是一个更加复杂一些的例子,每根手指放下的时候都会产生一个不同颜色的方块,手指动的时候方块跟着动,手指提起的时候方块消失,请下载查看试用。

通过附件所包含的实例,我们可以看出一些较为隐蔽的特性。首先,这里我们没有再使用event.touches取所有touch的对象,而是使用 event.changedTouches这个数组,用来取得所有跟本次事件相关的touch。但是,这里我发现一个奇怪的特性,不知道是我的ipad有 问题还是本来就是这样,就是在有多根手指放在屏幕上的时候,如果提起一根手指,touchend事件的changedTouches中会包含所有手指的 touch对象,然后,其他几根留在屏幕上的手指会重新触发touchstart,并刷新所有的touch对象(identifier都不一样了)。如果 这是一个所有设备都有的特性,那么将给编程者带来一些不便,不知道水果为啥要这么处理。

对touch event的介绍我们点到为止,这里给大家推荐两篇文档:

Safari dom additions reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariJSRef/Intro/Intro.html#//apple_ref/doc/uid/TP40001482-CH2g-BAJDAJAG

Safari web content guide:

http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebconten


多触式设备上特有的gesture event(android和iOS对这个事件的封装大同小异)。这个事件是对touch event的更高层的封装,和touch一样,它同样包括gesturestart,gesturechange,gestureend三个事件回调: 

gesturestart    当有两根或多根手指放到屏幕上的时候触发 

gesturechange    当有两根或多根手指在屏幕上,并且有手指移动的时候触发 

gestureend    当倒数第二根手指提起的时候触发,结束gesture 

   事件处理函数中会得到一个GestureEvent类型的参数,它包含了手指的scale(两根移动过程中分开的比例)信息和rotation(两根手指间连线转动的角度)信息。 

   当两根或以上的手指在屏幕上活动的时候,我们可以做出一些较为复杂的手势。这将涉及到普通的mouse事件,touch事件和gesture事件,情况比较复杂。touch已经在第一篇文章里详细介绍,这里就简单带过。 

   先看看当分别将两根手指放到屏幕上的时候,会触发哪些事件吧: 

1、第一根手指放下,触发touchstart,除此之外什么都不会发生(请参照第二篇文章,手指提起才会触发mouse的各事件) 

2、第二根手指放下,触发gesturestart 

3、触发第二根手指的touchstart 

4、立即触发gesturechange 

5、手指移动,持续触发gesturechange,就像鼠标在屏幕上移动的时候不停触发mousemove一样 

6、第二根手指提起,触发gestureend,以后将不会再触发gesturechange 

7、触发第二根手指的touchend 

8、触发touchstart!注意,和第一篇文章里介绍的一样,多根手指在屏幕上,提起一根,会刷新一次全局touch!重新触发第一根手指的touchstart,这点和苹果官方网站上介绍的不同。 

9、提起第一根手指,触发touchend 

   Gesture事件的处理和Touch类似,我们一般会在gesturechange的时候利用GestureEvent对象中的信息来做一些事情: 

var angle = event.rotation; 

var scale = event.scale; 

   这样能够取得scale和rotation信息,然后我们可以: 

e.target.style.webkitTransform = ‘scale(‘ + e.scale + startScale + ‘) rotate(‘ + e.rotation + startRotation + ‘deg)’; 

   这段代码能让element随着你的两根手指的运动而转动、伸展。以下是一段测试代码,请用ipad/iphone/android打开: 
http://wanglingshu.com/wp-content/uploads/ios-gesture.html 

   还有一件要说明的事情是,对于复杂手势,是否会触发某些鼠标事件?确实有,不过我只找到了一个。不管你的两根手指在屏幕上伸缩还是转动,都不会有任何鼠标事件触发,但当你的两根手指同时朝上或者朝下移动的时候,则会触发某些事件。请看下图: 

移动WEB开发高级touch事件[转]  

   两根手指同时向上或向下滚动,如果target element是一个scrollable element(也就是绑定了mousewheel的element)的话,将会触发mousewheel事件。如果不是scrollable element,则当手指停止移动的时候,会触发onscoll。这里请和第二篇文章的body scroll区别一下,如果你要滚动body,只需要一根手指轻轻拂动屏幕,但是你要滚动一个内部div或者iframe,则需要动用两根手指。 
   这也是多触式设备一个不太方便的地方。而对于我们开发者来说,这种不方便被放大了。。。因为从用户体验角度来说,要求用户使用两根手指滚动一个内部element显然是不合适的,而要实现像滚动body一样用一根手指优雅地滚动,我们必须利用touchevent,在它的回调函数中用代码来实现scroll。这里介绍一个段很不错的多触式滚动组件: 

http://cubiq.org/scrolling-div-on-iphone-ipod-touch 

   用起来很简单,new一个iScroll对象,传入需要滚动的inner element作为参数就行了。