在本文深入研究 iOS 和 Android 设备提供的触摸事件 API,探索一下可以构建哪些类型的应用,给出一些最佳做法,并论及一些使得可触控应用(touch-enabled application)的开发变得更加容易的有用技术。
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
js 的 touch 事件,一般用于移动端的触屏滑动
- $(function() {
- document.addEventListener("touchmove", _touch, false);
- }) function _touch(event) {
- alert(1);
- }
touchstart: 当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。
touchmove: 当手指在屏幕上滑动时连续的触发。在这个事件发生期间,调用 preventDefault() 可阻止滚动。
touchend: 当手指从屏幕上移开时触发。
touchcancel: 当系统停止跟踪触摸时触发。关于此事件的确切触发事件,文档中没有明确说明。
以上事件的 event 对象上面都存在如下属性:
touches: 表示当前跟踪的触摸操作的 Touch 对象的数组。
targetTouches: 特定于事件目标的 Touch 对象的数组。
changeTouches: 表示自上次触摸以来发生了什么改变的 Touch 对象的数组。
每个 Touch 对象包含下列属性:
clientX: 触摸目标在视口中的 X 坐标。
clientY: 触摸目标在视口中的 Y 坐标。
identifier:表示触摸的唯一 ID。
pageX:触摸目标在页面中的 x 坐标。
pageY:触摸目标在页面中的 y 坐标。
screenX: 触摸目标在屏幕中的 x 坐标。
screenY: 触摸目标在屏幕中的 y 坐标。
target: 触摸的 DOM 节点坐标
触摸事件
三种在规范中列出并获得跨移动设备广泛实现的基本触摸事件:
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:画出大约相当于手指形状的椭圆形。
可触控应用
touchstart、touchmove 和 touchend 事件提供了一组足够丰富的功能来支持几乎是任何类型的基于触摸的交互——其中包括常见的多点触摸手势,比如说捏缩放、旋转等待。 下面的这段代码让你使用单指触摸来四处拖曳一个 DOM 元素:
- var obj = document.getElementByIdx_x_x_x_x_x_x('id');
- obj.addEventListener('touchmove', function(event)
- { // 如果这个元素的位置内只有一个手指的话
- if (event.targetTouches.length == 1)
- {
- var touch = event.targetTouches[0];
- // 把元素放在手指所在的位置
- obj.style.left = touch.pageX + 'px';
- obj.style.top = touch.pageY + 'px';
- }
- }, false);
下面是一个示例,该例子显示了屏幕上当前所有的触点,它的作用就是用来感受一下设备的响应性。
- // 设置画布并通过ctx变量来暴露上下文复制代码
- canvas.addEventListener('touchmove',
- function(event) {
- for (var i = 0; i < event.touches.length; i++) {
- var touch = event.touches;
- ctx.beginPath();
- ctx.arc(touch.pageX, touch.pageY, 20, 0, 2*Math.PI, true);
- ctx.fill();
- ctx.stroke();
- }
- }, false);
演示
到处都有着许多有意思的多点触摸演示,比如说这个由 Paul Irish 和其他人实现的基于画布的绘画演示。
还有 Browser Ninja,一个技术演示,是一个使用了 CSS3 的转换、过渡和画布的 Fruit Ninja 克隆。
最佳做法
阻止缩放
缺省的多点触摸设置不是特别的好用,因为你的滑动和手势往往与浏览器的行为有关联,比如说滚动和缩放。
要禁用缩放功能的话,使用下面的元标记设置你的视图区(viewport),这样其对于用户来说就是不可伸缩的了:
content="width=device-width, initial-scale=1.0, user-scalable=no">
看看这篇关于移动 html 5 的文章,了解更多关于视图区设置的信息。
阻止滚动
一些移动设备有缺省的 touchmove 行为,比如说经典的 iOS overscroll 效果,当滚动超出了内容的界限时就引发视图反弹。这种做法在许多多点触控应用中会带来混乱,但要禁用它很容易。
- document.body.addEventListener('touchmove',
- function(event) {
- event.preventDefault();
- },
- false);
细心渲染
如果你正在编写的多点触控应用涉及了复杂的多指手势的话,要小心地考虑如何响应触摸事件,因为一次要处理这么多的事情。考虑一下前面一节中的在屏幕上画出所有触点的例子,你可以在有触摸输入的时候就立刻进行绘制:
- canvas.addEventListener('touchmove',
- function(event) {
- renderTouches(event.touches);
- },
不过这一技术并不是要随着屏幕上的手指个数的增多而扩充,替代做法是,可以跟踪所有的手指,然后在一个循环中做渲染,这样可获得更好的性能:
- var touches = [] canvas.addEventListener('touchmove',
- function(event) {
- touches = event.touches;
- },
- false);
- // 设置一个每秒60帧的定时器
- timer = setInterval(function() {
- renderTouches(touches);
- },
- 15);
提示:setInterval 不太适合于动画,因为它没有考虑到浏览器自己的渲染循环。现代的桌面浏览器提供了 requestAnimationFrame 这一函数,基于性能和电池工作时间原因,这是一个更好的选择。一但浏览器提供了对该函数的支持,那将是首选的处理事情的方式。
使用 targetTouches 和 changedTouches
要记住的一点是,event.touches 是与屏幕接触的所有手指的一个数组,而不仅是位于目标 DOM 元素上的那些。你可能会发现使用 event.targetTouches 和 event.changedTouches 来代替 event.touches 更有用一些。
最后一点,因为你是在为移动设备做开发,因此你应该要留心移动的最佳做法,这些在 Eric Bidelman 的文章中有论及,以及要了解这一 W3C 文档。
设备支持
遗憾的是,触摸事件的实现在完备性和质量方面的差别很大。我编写了一个诊断脚本来显示一些关于触摸 API 实现的基本信息,其中包括哪些事件是支持的,以及 touchmove 事件触发的解决方案。我在 Nexus One 和 Nexus S 硬件上测试了 Android2.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 次,所有的被测试设备都是这样。
来源: