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.jstree 增加节点的双击事件代码
Jul 27 Javascript
JS嵌套函数调用上下文的问题解决
Mar 26 Javascript
一个可以增加和删除行的table并可编辑表格中内容
Jun 16 Javascript
使用 js+正则表达式为关键词添加链接
Nov 11 Javascript
javascript设置和获取cookie的方法实例详解
Jan 05 Javascript
关于foreach循环中遇到的问题小结
May 08 Javascript
jquery tmpl模板(实例讲解)
Sep 02 jQuery
原生JS上传大文件显示进度条 php上传文件代码
Mar 27 Javascript
JavaScript设计模式之模板方法模式原理与用法示例
Aug 07 Javascript
jQuery实现的鼠标拖动浮层功能示例【拖动div等任何标签】
Dec 29 jQuery
微信小程序实现九宫格抽奖
Apr 15 Javascript
详解Vue-cli3 项目在安卓低版本系统和IE上白屏问题解决
Apr 14 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
火车采集器 免费版使出收费版本功能实现原理
2009/09/17 PHP
Yii2实现自定义独立验证器的方法
2017/05/05 PHP
二级域名或跨域共享Cookies的实现方法
2008/08/07 Javascript
div失去焦点事件实现思路
2014/04/22 Javascript
浅谈 jQuery 事件源码定位问题
2014/06/18 Javascript
js操作滚动条事件实例
2015/01/29 Javascript
jquery实现可横向和竖向展开的动态下滑菜单效果
2015/08/24 Javascript
Zero Clipboard实现浏览器复制到剪贴板的方法(多个复制按钮)
2016/03/24 Javascript
JS 实现倒计时数字时钟效果【附实例代码】
2016/03/30 Javascript
Json解析的方法小结
2016/06/22 Javascript
微信小程序 Video API实例详解
2016/10/02 Javascript
JS代码实现百度地图 画圆 删除标注
2016/10/12 Javascript
JavaScript实现数组降维详解
2017/01/05 Javascript
详解如何将angular-ui的图片轮播组件封装成一个指令
2017/05/09 Javascript
node中的cookie的具体使用
2018/09/13 Javascript
浅谈bootstrap layer.open中end的使用方法
2019/09/12 Javascript
Vue通过配置WebSocket并实现群聊功能
2019/12/31 Javascript
解决vue 退出动画无效的问题
2020/08/09 Javascript
JavaScript编码小技巧分享
2020/09/17 Javascript
[04:54]DOTA2 2017国际邀请赛:上届冠军WINGS采访短片
2017/08/09 DOTA
django中静态文件配置static的方法
2018/05/20 Python
celery4+django2定时任务的实现代码
2018/12/23 Python
pyqt 实现为长内容添加滑轮 scrollArea
2019/06/19 Python
Django项目基础配置和基本使用过程解析
2019/11/25 Python
如何给Python代码进行加密
2020/01/10 Python
Python print不能立即打印的解决方式
2020/02/19 Python
Python中的流程控制详解
2021/02/18 Python
HTML5给汉字加拼音收起展开组件的实现代码
2020/04/08 HTML / CSS
英国钻石公司:British Diamond Company
2020/02/16 全球购物
营销主管自我评价怎么写
2013/09/19 职场文书
开学典礼策划方案
2014/05/28 职场文书
2014年平安创建工作总结
2014/11/24 职场文书
2014年师德师风工作总结
2014/11/25 职场文书
人事行政主管岗位职责
2015/04/09 职场文书
2015年小学一年级班主任工作总结
2015/05/21 职场文书
PhpSpreadsheet中文文档 | Spreadsheet操作教程实例
2021/04/01 PHP