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

作者:junjie 时间:2024-04-26 17:13:17 

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

http://tools.aspxhome.com/table/javascript_event

标签:javascript,touch事件
0
投稿

猜你喜欢

  • vue项目部署到Apache服务器中遇到的问题解决

    2024-05-22 10:42:36
  • Golang汇编之控制流深入分析讲解

    2024-05-08 10:15:11
  • 怎样删除Git中缓存的用户名和密码

    2023-08-12 23:56:55
  • Mysql数据库备份和还原常用的命令

    2011-12-01 10:41:54
  • php操作SVN版本服务器类代码

    2023-09-08 07:22:41
  • 简单了解python模块概念

    2023-03-21 19:38:46
  • mysql 修改表结构 判断并添加column

    2010-10-25 20:07:00
  • Mysql my.ini 配置文件详解

    2024-01-28 06:16:57
  • 在Python3.74+PyCharm2020.1 x64中安装使用Kivy的详细教程

    2023-01-16 15:17:39
  • Python SQLAlchemy基本操作和常用技巧(包含大量实例,非常好)

    2022-03-02 16:50:47
  • jsp中文显示问号问题解决方法

    2023-07-22 10:33:50
  • Python面向对象程序设计OOP入门教程【类,实例,继承,重载等】

    2022-01-08 13:53:58
  • 解决python运行效率不高的问题

    2023-04-01 05:31:36
  • 使用torchtext导入NLP数据集的操作

    2023-08-19 16:07:10
  • Python通过递归获取目录下指定文件代码实例

    2021-02-24 15:08:51
  • Python设计模式之桥接模式原理与用法实例分析

    2022-03-18 19:02:16
  • 图像替换新技术:状态域方法[译]

    2009-08-06 16:41:00
  • 详解java调用ffmpeg转换视频格式为flv

    2024-01-19 03:13:11
  • Google中秋logo被恶搞

    2007-09-25 15:55:00
  • Linux系统(X64)安装Oracle11g完整安装图文教程另附基本操作

    2023-07-07 08:25:36
  • asp之家 网络编程 m.aspxhome.com