在触屏设备上,一些比较基础的手势都需要通过对 touch 事件进行二次封装才能实现。
zepto 是移动端上使用率比较高的一个类库,但是其 touch 模块模拟出来的一些事件存在一些兼容性问题,如 tap 事件在某些安卓设备上存在事件穿透的 bug,其他类型的事件也或多或少的存在一些兼容性问题。
于是乎,干脆自己动手对这些常用的手势事件进行了封装,由于没有太多真实的设备来进行测试,可能存在一些兼容性问题,下面的代码也只是在 iOS 7、Andorid 4 上的一些比较常见的浏览器中测试通过。
tap事件
tap 事件相当于 pc 浏览器中的 click 效果,虽然在触屏设备上 click 事件仍然可用,但是在很多设备上,click 会存在一些延迟,如果想要快速响应的 “click” 事件,需要借助 touch 事件来实现。
var startTx, startTy;element.addEventListener( 'touchstart', function( e ){ var touches = e.touches[0];
startTx = touches.clientX; startTy = touches.clientY; }, false );
element.addEventListener( 'touchend', function( e ){ var touches = e.changedTouches[0], endTx = touches.clientX, endTy = touches.clientY;
// 在部分设备上 touch 事件比较灵敏,导致按下和松开手指时的事件坐标会出现一点点变化 if( Math.abs(startTx - endTx) < 6 && Math.abs(startTy - endTy) < 6 ){ console.log( 'fire tap event' ); } }, false );
doubleTap事件
doubleTap 事件是当手指在相同位置范围内和极短的时间内两次敲击屏幕时触发的事件。在部分浏览器下,doubleTap 事件会选中文本,如果不希望选中文本,可以给元素添加 user-select:none 的 css 属性。
var isTouchEnd = false, lastTime = 0, lastTx = null, lastTy = null, firstTouchEnd = true, body = document.body, dTapTimer, startTx, startTy, startTime;element.addEventListener( 'touchstart', function( e ){ if( dTapTimer ){ clearTimeout( dTapTimer ); dTapTimer = null; }
var touches = e.touches[0];
startTx = touches.clientX; startTy = touches.clientY; }, false );
element.addEventListener( 'touchend', function( e ){ var touches = e.changedTouches[0], endTx = touches.clientX, endTy = touches.clientY, now = Date.now(), duration = now - lastTime;
// 首先要确保能触发单次的 tap 事件 if( Math.abs(startTx - endTx) < 6 && Math.abs(startTx - endTx) < 6 ){ // 两次 tap 的间隔确保在 500 毫秒以内 if( duration < 301 ){ // 本次的 tap 位置和上一次的 tap 的位置允许一定范围内的误差 if( lastTx !== null && Math.abs(lastTx - endTx) < 45 && Math.abs(lastTy - endTy) < 45 ){
firstTouchEnd = true; lastTx = lastTy = null; console.log( 'fire double tap event' ); } } else{ lastTx = endTx; lastTy = endTy; } } else{ firstTouchEnd = true; lastTx = lastTy = null; }
lastTime = now; }, false );
// 在 iOS 的 safari 上手指敲击屏幕的速度过快, // 有一定的几率会导致第二次不会响应 touchstart 和 touchend 事件 // 同时手指长时间的touch不会触发click
if( ~navigator.userAgent.toLowerCase().indexOf('iphone os') ){
body.addEventListener( 'touchstart', function( e ){ startTime = Date.now(); }, true );
body.addEventListener( 'touchend', function( e ){ var noLongTap = Date.now() - startTime < 501;
if( firstTouchEnd ){ firstTouchEnd = false; if( noLongTap && e.target === element ){ dTapTimer = setTimeout(function(){ firstTouchEnd = true; lastTx = lastTy = null; console.log( 'fire double tap event' ); }, 400 ); } } else{ firstTouchEnd = true; } }, true );
// iOS 上手指多次敲击屏幕时的速度过快不会触发 click 事件 element.addEventListener( 'click', function( e ){ if( dTapTimer ){ clearTimeout( dTapTimer ); dTapTimer = null; firstTouchEnd = true; } }, false );
}
longTap事件
longTap 事件是当手指长时间按住屏幕保持不动时触发的事件。
var startTx, startTy, lTapTimer;element.addEventListener( 'touchstart', function( e ){ if( lTapTimer ){ clearTimeout( lTapTimer ); lTapTimer = null; }
var touches = e.touches[0];
startTx = touches.clientX; startTy = touches.clientY;
lTapTimer = setTimeout(function(){ console.log( 'fire long tap event' ); }, 1000 );
e.preventDefault(); }, false );
element.addEventListener( 'touchmove', function( e ){ var touches = e.touches[0], endTx = touches.clientX, endTy = touches.clientY;
if( lTapTimer && (Math.abs(endTx - startTx) > 5 || Math.abs(endTy - startTy) > 5) ){ clearTimeout( lTapTimer ); lTapTimer = null; } }, false );
element.addEventListener( 'touchend', function( e ){ if( lTapTimer ){ clearTimeout( lTapTimer ); lTapTimer = null; } }, false );
swipe事件
swipe 事件是当手指在屏幕上滑动后触发的事件,根据手指滑动的方向又分为 swipeLeft (向左)、swipeRight (向右)、swipeUp (向上)、swipeDown (向下)。
var isTouchMove, startTx, startTy;element.addEventListener( 'touchstart', function( e ){ var touches = e.touches[0];
startTx = touches.clientX; startTy = touches.clientY; isTouchMove = false; }, false );
element.addEventListener( 'touchmove', function( e ){ isTouchMove = true; e.preventDefault(); }, false );
element.addEventListener( 'touchend', function( e ){ if( !isTouchMove ){ return; }
var touches = e.changedTouches[0], endTx = touches.clientX, endTy = touches.clientY, distanceX = startTx - endTx distanceY = startTy - endTy, isSwipe = false;
if( Math.abs(distanceX) >= Math.abs(distanceY) ){ if( distanceX > 20 ){ console.log( 'fire swipe left event' ); isSwipe = true; } else if( distanceX < -20 ){ console.log( 'fire swipe right event' ); isSwipe = true; } } else{ if( distanceY > 20 ){ console.log( 'fire swipe up event' ); isSwipe = true; } else if( distanceY < -20 ){ console.log( 'fire swipe down event' ); isSwipe = true; } }
if( isSwipe ){ console.log( 'fire swipe event' ); } }, false );
上面模拟的事件都封装在 MonoEvent 中了。完整代码地址:https://github.com/chenmnkken/monoevent,需要的朋友看看吧~
PS:这里再为大家推荐一款关于JS事件的在线查询工具,归纳总结了JS常用的事件类型与函数功能:
javascript事件与功能说明大全:
http://tools.jb51.net/table/javascript_event
本文向大家介绍移动web开发之touch事件实例详解,包括了移动web开发之touch事件实例详解的使用技巧和注意事项,需要的朋友参考一下 前面的话 iOS版Safari为了向开发人员传达一些特殊信息,新增了一些专有事件。因为iOS设备既没有鼠标也没有键盘,所以在为移动Safari开发交互性网页时,常规的鼠标和键盘事件根本不够用。随着Android 中的WebKit的加入,很多这样的专有事件变成了
本文向大家介绍javascript移动开发中touch触摸事件详解,包括了javascript移动开发中touch触摸事件详解的使用技巧和注意事项,需要的朋友参考一下 事件对象是用来记录一些事件发生时的相关信息的对象。事件对象只有事件发生时才会产生,并且只能是事件处理函数内部访问,在所有事件处理函数运行结束后,事件对象就被销毁! W3C DOM把事件对象作为事件处理函数的第一个参数传入进去 IE将
本文向大家介绍Javascript封装DOMContentLoaded事件实例,包括了Javascript封装DOMContentLoaded事件实例的使用技巧和注意事项,需要的朋友参考一下 最近在写一个Javascript的框架,刚把DOMContentLoaded事件封装好,略带小兴奋,把开发过程中遇到的原理和兼容性问题做篇笔记,省的忘记到处找。 我们在写js代码的时候,一般都会添加windo
本文向大家介绍移动设备web开发首选框架:zeptojs介绍,包括了移动设备web开发首选框架:zeptojs介绍的使用技巧和注意事项,需要的朋友参考一下 最近看到了一篇文章,是介绍一种新的js框架,名为zepto.js,他适用于移动设备已经桌面浏览器除了ie系列的。。 他兼容jquery的API,所以学起来或用起来并不吃力。他比jquery的优势在于 1.他够小,只有21k左右。。功能俱全。 2
问题内容: 我已经与React互动了几个月了,但是遇到了一些奇怪的事情。 在移动设备上根本不会触发点击事件: http://jsbin.com/morarewelu/1/edit?html,js,输出 http://jsbin.com/morarewelu/1/-在您的设备上检查 您可以看到该点击从未触发。在iPhone上进行测试。 这是预期的行为,还是仅仅是一个错误? 问题答案: React的G
Touch 简介 Touch(触摸芯片)是 UI 设计中进行人机交互重要的一部分,一个完整的 UI 设计应该包括输入信息和输出信息,LCD 等屏幕设备负责显示输出,那么 Touch 设备就负责触点信息采集作为信息输入。 Touch 设备与主机通讯一般都是采用 I2C 总线协议来进行数据交互,所以一个 Touch 设备,就是一个标准的 I2C 从设备,而且为了提高接收 Touch 数据的实时性,触摸