javascript移动设备Web开发中对touch事件的封装实例


Posted in Javascript onJune 05, 2014

在触屏设备上,一些比较基础的手势都需要通过对 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事件与功能说明大全:

Javascript 相关文章推荐
jquery 学习之二 属性相关
Nov 23 Javascript
Extjs4中tree的拖拽功能(可以两棵树之间拖拽) 简单实例
Dec 08 Javascript
Event altKey,ctrlKey,shiftKey属性解析
Dec 18 Javascript
深入浅析JSON.parse()、JSON.stringify()和eval()的作用详解
Apr 03 Javascript
js通过keyCode值判断单击键盘上某个键,然后触发指定的事件方法
Feb 19 Javascript
ES6入门教程之Iterator与for...of循环详解
May 17 Javascript
使用vue官方提供的模板vue-cli搭建一个helloWorld案例分析
Jan 16 Javascript
Vue导出页面为PDF格式的实现思路
Jul 31 Javascript
JavaScript事件冒泡与事件捕获实例分析
Aug 01 Javascript
利用vue.js把静态json绑定bootstrap的table方法
Aug 28 Javascript
js回文数的4种判断方法示例
Jun 04 Javascript
Vue+Openlayers自定义轨迹动画
Sep 24 Javascript
删除条目时弹出的确认对话框
Jun 05 #Javascript
判断复选框是否被选中的两种方法
Jun 04 #Javascript
jQuery页面加载初始化常用的三种方法
Jun 04 #Javascript
JS替换字符串中字符即替换全部而不是第一个
Jun 04 #Javascript
ActiveX控件与Javascript之间的交互示例
Jun 04 #Javascript
使用jquery修改表单的提交地址基本思路
Jun 04 #Javascript
jQuery操作元素css样式的三种方法
Jun 04 #Javascript
You might like
一个简洁的PHP可逆加密函数(分享)
2013/06/06 PHP
PHP设计模式之结构模式的深入解析
2013/06/13 PHP
php使用GD实现颜色渐变实例
2015/06/02 PHP
php设计模式之单例模式用法经典示例分析
2019/09/20 PHP
PHP实现简易用户登录系统
2020/07/10 PHP
jQuery UI Datepicker length为空或不是对象错误的解决方法
2010/12/19 Javascript
解决javascript:window.close()在chrome,Firefox下失效的问题
2013/05/07 Javascript
JavaScript中document.forms[0]与getElementByName区别
2015/01/21 Javascript
jQuery制作效果超棒的手风琴折叠菜单
2015/04/03 Javascript
JavaScript的MVVM库Vue.js入门学习笔记
2016/05/03 Javascript
js实现统计字符串中特定字符出现个数的方法
2016/08/02 Javascript
Javascript封装id、class与元素选择器方法示例
2017/03/13 Javascript
axios基本入门用法教程
2017/03/25 Javascript
Vue.js展示AJAX数据简单示例讲解
2017/03/29 Javascript
jQuery实现select下拉框获取当前选中文本、值、索引
2017/05/08 jQuery
Vue使用vue-cli创建项目
2017/09/01 Javascript
详解Vue中watch的高级用法
2018/05/02 Javascript
vue组件实践之可搜索下拉框功能
2018/11/25 Javascript
vue实现动态显示与隐藏底部导航的方法分析
2019/02/11 Javascript
微信小程序中如何使用flyio封装网络请求
2019/07/03 Javascript
javascript面向对象三大特征之封装实例详解
2019/07/24 Javascript
python抓取京东价格分析京东商品价格走势
2014/01/09 Python
python基础教程之基本数据类型和变量声明介绍
2014/08/29 Python
对Python信号处理模块signal详解
2019/01/09 Python
对Pycharm创建py文件时自定义头部模板的方法详解
2019/02/12 Python
python 魔法函数实例及解析
2019/09/25 Python
python分布式编程实现过程解析
2019/11/08 Python
python 图像的离散傅立叶变换实例
2020/01/02 Python
Python实现名片管理系统
2020/02/14 Python
加拿大购物频道:The Shopping Channel
2016/07/21 全球购物
美国新兴城市生活方式零售商:VILLA
2017/12/06 全球购物
英国羊皮鞋类领先品牌:Just Sheepskin
2019/12/12 全球购物
瀑布模型都有哪些优缺点
2014/06/23 面试题
抗洪救灾先进集体事迹材料
2014/05/26 职场文书
小学一年级学生评语大全
2014/12/25 职场文书
世界各国短波电台对东亚播送时间频率表(SW)
2021/06/28 无线电