这篇文章主要介绍了javascript移动设备Web开发中对touch事件的封装实例,分别对tap事件、doubleTap事件、longTap事件、swipe事件做了封装,需要的朋友可以参考下

在触屏设备上,一些比较基础的手势都需要通过对 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,需要的朋友看看吧~

最新资讯
瑞幸咖啡任命麦楷博平为独立审计方 取代安永

瑞幸咖啡任命麦楷博平

瑞幸咖啡宣布任命独立会计师事务所Marcum Bernstein &
石正丽:病毒溯源很重要,但可能永远找不到

石正丽:病毒溯源很重要

病毒溯源是一件非常重要的事,因为新冠病毒是一个新型冠
团车网第二季度营收5470万元 同比下滑73%

团车网第二季度营收54

团车网(Nasdaq:TC)今日发布了截至6月30日的2020年第二季
长期主义者阿里巴巴

长期主义者阿里巴巴

从某种意义上来说,阿里其实是一家活在明天的公司。
阿里互娱证实将升级为独立事业群

阿里互娱证实将升级为

据《晚点 LatePost》独家获悉,阿里巴巴游戏业务所属的
蚂蚁集团首发过会,从IPO受理到正式过会仅用时25天

蚂蚁集团首发过会,从IP

科创板上市委9月18日公告称,蚂蚁集团、奥普特首发过会
最新文章
详解Vue的ref特性的使用

详解Vue的ref特性的使

这篇文章主要介绍了详解Vue的ref特性的使用,文中通过
vue学习笔记之slot插槽基本用法实例分析

vue学习笔记之slot插

这篇文章主要介绍了vue学习笔记之slot插槽基本用法,结
vue跳转方式(打开新页面)及传参操作示例

vue跳转方式(打开新页

这篇文章主要介绍了vue跳转方式(打开新页面)及传参操作,
vue学习笔记之过滤器的基本使用方法实例分析

vue学习笔记之过滤器

这篇文章主要介绍了vue学习笔记之过滤器的基本使用方
js获取本日、本周、本月的时间代码

js获取本日、本周、本

本篇文章给大家分享的内容是利用js如何获取本日、本周
node crawler如何添加promise支持

node crawler如何添加

这篇文章主要介绍了node crawler如何添加promise支持,