移动端事件touchstart、touchmove、touchend详解

39,794 阅读4分钟

在PC端上的JS事件相信大家已经熟悉不少,诸如click\mouseover这类事件,都可以满足交互的需要,虽然移动端上的事件可能平常稍有接触,但是可能不太了解其中具体的用法区别。

前言:

这几个事件最早出现于IOS safari中,为了向开发人员转达一些特殊的信息,所以新增了这些事件,随着Android中的webkit的加入,慢慢地这样的专有事件成了事实的标准,从而导致W3C开始指定Touch Event规范的内容。

具体说来有这样几个事件:

  • touchstart 手指触摸屏幕时触发,即使已经有手指在屏幕上也会触发。
  • touchmove 手指在屏幕滑动时触发。
  • touchend 手指从屏幕时移开时触发。

事件定义的方式:

大致上分为DOM0事件和DOM2事件两种.

DMO0事件,就是传统的直接将事件作为属性设置的形式:

 div1.ontouchstart = function(){
     alert(1);
 }

DOM2事件,则是用addEventListener的方式来绑定事件处理程序:

  div1.addEventListener("touchstart",function(){
      alert(1);
  });

大多数时候不推崇第一种方式,这种方式在移动端使用时好时坏,不建议使用。

PC的事件比移动端上的事件响应的慢300ms:

在早期的手机上,浏览器为了能够实现放大和缩放功能,采用双击的方式来达到这样的交互效果,为了实现这样的效果,浏览器需要判断用户在第一次触碰屏幕之后,是否在300ms之内再次点击,有则表明用户希望缩放和放大,所以click事件会推迟到300ms之后运行。

        var div = document.querySelector("#div");
        div.onclick = function(){
            console.log("click!");
        }
        div.ontouchstart = function(){
            console.log("touchstart!");
        }

可以看到每次点击,touchstart总会先于click事件运行。 当然这方面的问题有专门的库用于解决延迟的问题。诸如:Fastclick

点击穿透问题:

这个问题在当有一个绝对定位或固定定位元素绑定了touch事件,那么覆盖在他之下的具有点击特性的元素也会被触发。

比如:
有一个遮罩层A元素,他的底下有一个链接元素B.
当这个遮罩层点击之后希望遮罩层消失,真实的状况是这时候点击遮罩层不见的同时会跳转页面。

这是为什么? 前面说过了touchstart会先于click事件执行,当上述的这个遮罩层消失在300ms之内消失时,那么他底下的具有点击特性的元素会被触发。大家可以私下模拟上述的例子。

如何解决?

下层元素不使用点击特性的元素

我可以去某宝的移动版网站上看,他首页使用的多层的DIV来代替A标签

这种方法不太推荐,因为a标签能够为SEO提供一些信息

阻止所有点击:

document.addEventListener("click",function(ev){
 ev.preventDefault();
})
document.addEventListener("touchstart",function(ev){
 ev.preventDefault();
})

这时候的有点击特性的元素的交互行为将会失效,当然也可以根据实际需要重新开启交互行为。

代码如下:

a.ontouchstart = function(){
        window.location = this.href;
 }

这样既兼顾了SEO又可以安然使用点击事件。当然它还有其他的好处。

  • 能够阻止IOS10缩放: 对于ISO10设置meta标签禁止缩放是没有作用的,上面的代码阻止了浏览器的默认行为。
  • 阻止IOS10下回弹效果
  • 去除系统滚动条
  • 禁止长按选中文字和图片:当然也同时阻止了input获取焦点的行为,这就需要使用单独为input添加一个阻止冒泡的行为。以免事件冒泡至顶层元素而被阻止交互行为。
input.ontouchstart = function(ev){
      ev.stopPropagation();
}

移动端事件对象:

注意到前面的例子里每一个事件处理程序都有一个evt的参数了吗,那是有关于当前触摸的相关信息,通过这样一个对象,能够获取到当前触碰的坐标,触碰的手指个数等等。 其中最重要的常用的莫过于手指列表了。

touches:当前位于屏幕下的手指列表信息
targetTouches: 当前位于当前元素下的手指列表信息
changedTouches: 当前涉及到当前事件的手指列表

这三个手指列表都存在触碰事件对象里面,在每次发生触碰之后这里的列表都会更新。

var div = document.querySelector("#div");
         div.ontouchmove = function(evt){
            this.innerHTML = `
                touches-length:${evt.touches.length}
                targetTouches-length:${evt.targetTouches.length}
                changedTouches-length:${evt.changedTouches.length}
                `
            console.log(evt);
        }

以上实例,在手指移动于DIV上之后会更新DIV的内容。 分别展示了touches、targetTouches、changedTouches的手指个数

感谢阅读!希望能共同进步!