5.移动端事件

278 阅读21分钟

移动端事件基础介绍

前面我们已经了解了移动端的适配以及响应式布局相关知识,从这一章开始,我们就要进入到移动端另外一个非常重要的章节“移动端事件”了。

本文将介绍以下内容:

  • 移动端有哪些事件
  • 事件对象
  • 移动端事件和 PC 端事件区别
  • 事件穿透
  • 阻止默认行为带来的影响

移动端有哪些事件

在学习 PC 端的时候,我们已经接触过事件了,而到了移动端,又有了新的事件,分别为:

  • touchstart:手指按下事件,类似 mousedown
  • touchmove:手指移动事件,类似 mousemove
  • touchend 手指抬起事件,类似 mouseup

例如:

<div class="container"></div>
* {
  margin: 0;
  padding: 0;
}

.container {
  width: 200px;
  height: 200px;
  background-color: red;
}
var box = document.querySelector('.container');
box.addEventListener('touchstart', () => {
  console.log('手指按下去了');
});
box.addEventListener('touchmove', () => {
  console.log('手指滑动了');
});
box.addEventListener('touchend', () => {
  console.log('手指抬起了');
});

事件对象

之前在学习事件的时候,有一个非常重要的东西,那就是事件对象。通过事件对象,我们可以获取到本次事件发生时,一些更加具体的信息。上面所介绍的移动端事件,自然也是有事件对象传入回调函数的。例如:

box.addEventListener('touchstart', (e) => {
  console.log(e);
});

此时我们打印传入的事件对象,可以看到如下的信息:

image-20220322085244821

可以看到,事件对象中一如既往的包含了很多信息,其中对于我们开发来讲比较重要的就是如下 3 个信息:

changedTouchestargetTouchestouches3 个对应的值都是 TouchList(手指列表)

  • changedTouches:触发当前事件的手指列表,也就是涉及当前(引发)事件的触摸点的列表
  • targetTouches:位于当前 DOM 元素上的手指列表,也就是当前对象上所有触摸点的列表
  • touches:位于当前屏幕上的所有手指列表(必需至少有 1 个手指在添加触发事件的元素上),也就是当前屏幕上所有触摸点的列表

通过一个例子来区分一下触摸事件中的这三个属性:

比如 div1、div2 只有 div2 绑定了 touchstart 事件,第一次放下一个手指在 div2 上,触发了 touchstart 事件,这个时候,三个集合的内容是一样的,都包含这个手指的 touch,然后,再放下两个手指一个在 div1 上,一个在 div2 上,这个时候又会触发事件,但 changedTouches 里面只包含第二个第三个手指的信息,因为第一个没有发生变化,而 targetTouches 包含的是在第一个手指和第三个在 div2 上的手指集合,touches 包含屏幕上所有手指的信息,也就是三个手指。

网上有个灵魂画手对此做了一个绘制:

touches

移动端事件和 PC 端事件区别

虽说有了移动端专属的事件,并不意味着原本 PC 端的浏览器事件就不能用了,但是还是推荐尽量使用移动端的专属事件,因为 PC 端的事件并不是专门为移动端设计的,因此会存在各种各样的问题,其中一个比较出名的就是移动端 300ms 延迟。

为什么移动端点击事件要加 300ms 延迟呢?

早在 2007 年初,苹果公司在发布首款 iPhone 前夕,遇到一个问题:当时的网站都是为大屏幕设备所设计的。于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题。

这当中最出名的,当属双击缩放( double tap to zoom ),这也是会有上述 300 毫秒延迟的主要原因。

双击缩放,顾名思义,即用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。 那么这和 300 毫秒延迟有什么联系呢?

假定这么一个场景: 用户在 iOS Safari 里边点击了一个链接。由于用户可以进行双击缩放或者双击滚动的操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。

鉴于 iPhone 的成功,其他移动浏览器都复制了 iPhone Safari 浏览器的多数约定,包括双击缩放,几乎现在所有的移动端浏览器都有这个功能。

下面我们能够来看一下这个问题

var box = document.querySelector('.container');
box.addEventListener('click', () => {
  console.log('click 事件触发');
});
box.addEventListener('touchstart', () => {
  console.log('touchstart 事件触发');
});

2014 年,从 Chrome32 开始 Google 已经解决这个 300ms 延迟问题,只要定义了 viewport 就不会有 300ms 延迟问题。

除此之外,我们来看一下移动端事件和 PC 端事件之间的其他区别。虽然上面介绍的 3 个移动端事件,都能找到其在 PC 端中相似的事件,但是仔细一比较,也是存在如下区别的:

  • 触发点区别
  • 触发顺序的区别
  • touchstartclick 的区别
触发点区别

PC

  • mousemove:不需要鼠标按下,但是必需在元素上才能触发

  • mouseup:必需在元素上抬起才能触发

移动端

  • touchmove:必需手指按下才能触发,但是,按下后不在元素上也能触发

  • touchend:不需要在元素上抬起就能触发

触发顺序

触发顺序依次为:touchstart → touchend → mousedown → click → mouseup

并且 PC 的事件在移动端里会有 300ms左右 延迟

touchstartclick 的区别

touchstart 为手指碰到元素就触发,click 为手指碰到元素并且抬起才会触发

事件穿透

所谓事件穿透,是移动端上面一个非常有名的 Bug,其出现场景为:有两层重叠的元素,上面的元素有 touch 事件(点击后要消失),下面是一个默认会触发 click 事件的元素(a、表单元素、带 click 事件的元素),此时点击上一层的元素,下一层也同样会被点击。

来看一个例子:

<a href="http://www.baidu.com/">度娘</a><br>
<input type="text">
<p>这是一个段落</p>
<div class="container"></div>
* {
    margin: 0;
    padding: 0;
}

.container {
    width: 200px;
    height: 200px;
    background: green;
    color: #fff;
    position: absolute;
    left: 0;
    top: 0;
    opacity: 0.5;
}

input {
    border: 1px solid #000;
}
var box = document.querySelector('.container');
box.addEventListener('touchstart', () => {
  box.style.display = 'none';
});

const p = document.querySelector('p');
p.addEventListener('click', () => {
  alert('该段落被点击了');
});

为什么会存在事件穿透呢?

这是因为在移动端浏览器,事件执行的顺序是 touchstarttouchmovetouchedclick。而 click 事件有 300ms 的延迟,当 touchstart 事件把上层元素隐藏之后,隔了 300ms,浏览器触发了 click 事件,但是此时上层元素不见了,所以该事件被派发到了下层元素身上。

那么既然存在这个问题,该如何解决呢?

有一个最简单的解决方式,那就是取消事件的默认行为,如下:

box.addEventListener('touchstart', ev => {
  box.style.display = 'none';
  ev.preventDefault(); // 取消事件的默认动作
});

当我们阻止了 touchstart 事件的默认行为后,事件穿透也就随即消失。

阻止默认行为带来的影响

在上面,我们虽然使用事件对象的 preventDefault 方法来阻止元素的默认行为。

在移动端,不仅元素身上绑定了默认事件,在 document 身上也绑定了默认事件,因此我们可以利用冒泡事件来阻止默认事件,也就是说哪怕你元素本身没有阻止默认事件,你触发了默认事件,但是通过冒泡父元素身上取消了默认事件,那么最终的结果默认事件也会被取消掉,因为根据事件流,元素身上的事件在目标阶段触发,冒泡事件在冒泡阶段触发,冒泡阶段在目标阶段之后,最终结果取决于后执行的事件。利用这个思想我们就可以通过在 document 身上取消默认事件,从而阻止所有的默认事件。

虽然我们阻止掉了所有的默认事件,但是这种方法也带来了新的问题:

touchmove

  • 阻止了浏览器的滚动条

  • 阻止了用户双指缩放

touchstart

  • 解决 IOS10+ 及部分安卓机通过设置 viewport 禁止用户缩放的功能(双指滑动、双击)
  • 解决事件点透问题
  • 阻止图片文字被选中
  • 阻止了长按元素会弹出系统菜单
  • 阻止了浏览器回弹的效果
  • 阻止了浏览器的滚动条
  • 阻止了鼠标的事件
  • 阻止了 input 框的输入功能

我们可以通过下面的例子来看到部分功能已经失效。

<div class="page">
  <img src="./ok.png" alt="" width="100%">
  <input type="text">
  <ul>
    <li><a href="http://www.baidu.com">度娘</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
    <li><a href="#">这是一个很长很长的链接</a></li>
  </ul>
</div>
body {
    margin: 0;
}

ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

li {
    line-height: 50px;
}

li a {
    font-size: 30px;
}

input {
    border: 1px solid #000;
}
const page = document.querySelector('.page');
page.addEventListener('touchstart', ev => {
  ev.preventDefault();
});

另外,如果是在 document 上面阻止默认事件,例如将上面的 JavaScript 修改如下:

document.addEventListener('touchstart',ev=>{
 	ev.preventDefault();
});

会发现在 chrome 移动端模拟器或者手机浏览器上事件的默认行为并没有成功阻止。其中 preventDefault 不生效问题就是由 passive 这个参数引起的。

tartget.addEventListener(type, listener, {
     capture: Booolean,
     once: Boolean,
     passive: Boolean,
     signal: AbortSignal
})

为什么呢?

事件监听器在监听事件时,并不能提前知道回调函数中是否会阻止默认行为,因此若想知道是否会阻止就需要等待函数执行完,这段时间虽然很短,但等待仍会让人感到卡顿。

passive

于是我们可以通过传递 passivetrue 来明确告诉浏览器,事件处理程序不会调用 preventDefault 来阻止默认滑动行为。而大部分事件监听器是不会阻止默认行为的,因此某些浏览器就将一些节点(例如 document)事件的 passive 默认设置为为 true

因此要解决上面 document 上无法阻止默认行为的情况,只需要将 passive 设置为 false 即可。即明确告诉浏览器,事件处理程序会调用 preventDefault 来阻止默认滑动行为。

document.addEventListener('touchstart', ev => {
	ev.preventDefault();
}, { passive: false });

回到之前的话题,在父元素上面阻止元素默认行为,会导致很多元素的默认行为也没有了,那么此时该怎么办呢?

比如在获取验证码时,验证码通常用户希望是能够复制的,因此会触发长按复制的默认事件,这个事件我们希望在这个元素身上不被阻止掉,那么应该如何实现?

有一种方案是阻止冒泡。如上面所述,我们是通过冒泡来借助父元素阻止掉默认事件,那么如果我们切断冒泡,那么父元素身上的阻止默认事件就无法被触发,元素本身的默认事件就无法被阻止掉了。

但是这样也只是解决了其中一个问题,上面还罗列出了很多其他问题,例如所有的滚动条失效,这些问题该怎么解决呢?

实际上,移动端进行开发时一上来就需要阻止所有的默认事件,后面的很多功能都需要我们自定义来实现


2. 滑屏操作与轮播图

在上一讲中,我们介绍了移动端事件的一些基本知识,也知道了移动端中如果在 document 上面阻止了默认事件的话,又会出现很多新的问题,例如 a 标签无法跳转,表单输入控件无法选中。这些问题都需要我们自己来解决。

例如:a 标签无法跳转

dom.addEventListener('touchstart',e=>{
  location.href = e.target.href;
})

表单输入控件无法选中

input.addEventListener('touchstart',ev=>{
  input.focus();
})

这些问题我们倒还是能够很轻松的解决。

但是其中有一条是连基本的滑动都会被阻止掉了,因此同样,滑屏也只有通过我们自己手动实现。

本小节我们来看一个移动端中常见的操作:滑屏。并且在此基础上来实现一个轮播图。

本文主要介绍以下内容:

  • 滑屏操作
  • 轮播图

滑屏操作

还记得上一小节中我们所说的,在移动端中我们要阻止所有的默认事件,这样就能解决一些诸如事件穿透的 Bug。但是这随之而来的带给我们一些新的问题:那就是阻止了默认行为之后,很多东西都失效了,例如滚动条失效,因此,很多功能都需要我们自定义来实现。

这里我们就来实现一个滑屏操作。

实际上,滑屏操作的原理并不难理解,就和以前在 PC 端所书写的拖动是一样的。

首先我们复习一下事件对象中的 changedTouches 属性,该属性可以获取当前(引发)事件的触摸点的列表。列表的每一项为一个 Touch 对象,里面有那么一些属性,如下:

image-20220401114400079

关于 Touch 对象各属性的含义,可以参阅 MDNdeveloper.mozilla.org/zh-CN/docs/…

下面是一段滑屏操作的示例代码:

<div id="wrap">
  <ul id="list">
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表10</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表1</a></li>
    <li><a href="#">这是一个很长很长的列表20</a></li>
  </ul>
</div>
body{
  margin: 0;
}
ul{
  margin: 0;
  padding: 0;
  list-style: none;
}

#wrap{
  height: 100vh;
  overflow: hidden;
  border: 5px solid #f00;
  box-sizing: border-box;
}

#list{
  transition: 0.3s;
}
#list li{
  font-size: 24px;
  line-height: 50px;
}
var wrap=document.querySelector('#wrap'),
    list=document.querySelector('#list');
var startPointY=0,		//按下时手指的坐标
    startTop=0,			//按下时元素的距离
    movePointY=0;		//手指移动时的坐标

Transform(list);	//使用第三方的库,在一上来的时候设置一下初始的距离

wrap.addEventListener('touchstart',ev=>{
  startPointY=ev.changedTouches[0].pageY;	//按下的时候获取手指的坐标
  startTop=list.translateY;
});

wrap.addEventListener('touchmove',ev=>{
  //坐标移动的距离 = 当前的距离-按下时的距离
  movePointY=ev.changedTouches[0].pageY-startPointY;

  //元素走的距离=按下时元素的距离+坐标移动的距离
  list.translateY=startTop+movePointY;

  ev.preventDefault();
});

因为滑屏操作涉及到频繁的滑动,而以前传统的通过 position 的方式来实现的话,会有重绘重排的性能问题,因此我们选择使用 CSS3transform 来实现滑动效果,CSS3 新增的 transform 有硬件加速等特性,性能上面要比传统的 position 要好一些。

另外,在上面的代码中,我们用到了一个第三方库 Transformgithub.com/AlloyTeam/P…

轮播图

接下来我们在滑屏操作上更进一步,来实现一个轮播图。

其原理如下图所示:

image-20220401160337640

代码如下:

<section id="banner">
  <div class="wrap">
    <a href="#"><img src="images/banner_01.jpg" alt=""></a>
    <a href="#"><img src="images/banner_02.jpg" alt=""></a>
    <a href="#"><img src="images/banner_03.jpg" alt=""></a>
  </div>
  <div class="circle">
    <span class="active"></span><span></span><span></span>
  </div>
</section>
body {
  margin: 0;
}

#banner {
  position: relative;
  width: 100vw;
  overflow: hidden;
}

.wrap {
  width: 300vw;
  display: flex;
}

.wrap a {
  width: 100vw;
}

.wrap a img {
  width: 100%;
  vertical-align: middle;
}

.circle {
  position: absolute;
  bottom: 3vw;
  width: 100vw;
  display: flex;
  justify-content: center;
}

.circle span {
  width: 3vw;
  height: 3vw;
  background: #ddd;
  border-radius: 50%;
  margin: 0 1.5vw;
}

.circle span.active {
  background: grey;
  opacity: .8;
}
var banner = document.querySelector('#banner'),
    wrap = document.querySelector('.wrap'),
    spans = document.querySelectorAll('.circle span'),
    imgWidth = banner.offsetWidth; // 一张图片的宽度

var startPointX = 0, // 按下时手指的坐标
    disPointX = 0, // 手指坐标的差
    startEleX = 0, // 按下时元素的位置
    cn = 0, // 当前图片走的索引数
    ln = 0; // 上一个图片走的索引

Transform(wrap);

//无缝滚动
wrap.innerHTML += wrap.innerHTML; //复制了一份
wrap.style.width = wrap.children.length * imgWidth + 'px';

banner.addEventListener('touchstart', ev => {
  startPointX = ev.changedTouches[0].pageX;

  // 按下的是第 0 张图,要做的事情:让 wrap 走到第 2 份的第 0 张,左边就有内容
  if (cn == 0) {
    cn = wrap.children.length / 2;
  }

  // 按下的是最后一张图,要做的事情:让 wrap 走到第 1 份的最后一张图
  if (cn == wrap.children.length - 1) {
    cn = wrap.children.length / 2 - 1;
  }
  wrap.style.transition = ''; // 不去掉的放在拖动的时候会很慢
  // 当改变了 cn 的值后也需要修正一下 wrap 的位置, 使其马上变过去,以免两边出现留白
  wrap.translateX = -imgWidth * cn;
  startEleX = wrap.translateX; // 当 wrap 的位置改变后,需要去更新一下初始值(元素的位置)
  ev.preventDefault();
});

banner.addEventListener('touchmove', ev => {
  disPointX = ev.changedTouches[0].pageX - startPointX;

  wrap.translateX = startEleX + disPointX;
});

banner.addEventListener('touchend', ev => {
  // 回弹的效果
  var backWidth = imgWidth / 8; //加弹的距离,超过这个距离才能运动到下一张,小于这个距离就需要回弹

  if (Math.abs(disPointX) > backWidth) {
    // 这个条件满足了说明现拖动的距离已经超过回弹的距离了,可以运动到下一张了
    // 判断现在是往右边拖还是往左边拖
    if (disPointX < 0) {
      // 往左边拖
      cn++;
    }

    if (disPointX > 0) {
      // 往右边拖
      cn--;
    }
  }

  wrap.style.transition = '0.3s';
  wrap.translateX = -imgWidth * cn;

  //修改小圆点的class
  /* 
                现在图片的索引:0,1,2,3,4,5 => 0,1,2,0,1,2
                span标签的索引:0,1,2
            */

  // 先去掉上一个次圆点身上的class
  spans[ln].className = '';
  // 先去掉上一个次圆点身上的class
  spans[cn % (wrap.children.length / 2)].className = 'active';
  // 再最后的时候需要去更新一下上一个的索引,更新为这次。相对于下次来说,它的上一次是不是就是当前次
  ln = cn % (wrap.children.length / 2);
});

移动端第三方库

在做 PC 端的开发时,我们往往会用到第三方库,这样可以大大的提升我们的开发效率。

而在做移动端页面时,同样存在非常好用的第三方库,本小节我们就一起来看两个在移动端开发中非常有名的第三方库:

  • Swiper.js 轮播图库
  • 移动端手势库

Swiper.js 轮播图库

在上一节课中,我们实现了移动端中常见的滑屏和轮播图。

有一些比较成熟的库,可以提升我们的开发效率。这里首先要介绍的第一个库就是来自我们国人开发的 Swiper.js

官网地址:www.swiper.com.cn/

这是一个非常方便的制作轮播图的的第三方库,支持各种姿势的轮播,很多大厂也是在自己的移动端网页中使用这个库。

image-20220330234611358

移动端手势库

Hammer.js 是一款开源的移动端第三方库,Hammer.js 不需要依赖任何其他的 JS 框架或者库,并且整个框架非常小,v2.0.4 版本只有 3.96kb

Hammer.js 官网地址:hammerjs.github.io/

image-20220331091845292

Hammer.js 可以完美的实现在移端开发的大多数事件,如:点击、滑动、拖动、多点触控等事件。

Hammer.js 在使用时非常简单,示例如下:

<div id="test" class="test"></div>
//创建一个新的hammer对象并且在初始化时指定要处理的dom元素
var hammertime = new Hammer(document.getElementById("test"));
//为该dom元素指定触屏移动事件
hammertime.on("pan", function (ev) {
  //控制台输出
  console.log(ev);
});

Hammer.js 主要事件如下:

image-20220330235011654

Rotate 事件

在指定的 dom 区域内,当两个手指或更多手指成圆型旋转时触发(就像两个手指拧螺丝一样)。

  • Rotate:所有旋转的集合
  • Rotatestart:旋转开始
  • Rotatemove:旋转过程
  • Rotateend:旋转结束
  • Rotatecancel:旋转取消
<div id="test" class="test">事件区域</div>
<div id="result" class="result">事件结果:旋转触发<br /></div>
html,
body {
  width: 100%;
  height: 100%;
  margin: 0px;
  padding: 0px;
}

.test {
  width: 100%;
  height: 50%;
  background: #ffd800;
  text-align: left;
}

.result {
  width: 100%;
  height: 50%;
  background: #b6ff00;
  text-align: left;
}
// 创建一个新的 hammer 对象并且在初始化时指定要处理的 dom 元素
var hammertime = new Hammer(document.getElementById("test"));
// 为该 dom 元素指定触屏旋转事件
hammertime.add(new Hammer.Rotate());
// 添加事件
hammertime.on("rotate", function (e) {
  document.getElementById("result").innerHTML += "X偏移量:【" + e.deltaX + "】,Y偏移量:【" + e.deltaY +
    "】<br />";
  //控制台输出
  console.log(e);
});

Pinch 事件

在指定的 dom 区域内,两个手指(默认为两个手指,多指触控需要单独设置)或多个手指相对(越来越近)移动或相向(越来越远)移动时事件。除了 Pinch 事件以外,该事件事以分别对以下事件进行监听并处理:

  • Pinchstart:多点触控开始
  • Pinchmove:多点触控过程
  • Pinchend:多点触控结束
  • Pinchcancel:多点触控取消
  • Pinchin:多点触控时两手指距离越来越近
  • Pinchout:多点触控时两手指距离越来越远
<div id="test" class="test">事件区域</div>
<div id="result" class="result">事件结果:捏合触发<br /></div>
// 创建一个新的 hammer 对象并且在初始化时指定要处理的dom元素
var hammertime = new Hammer(document.getElementById("test"));
// 为该 dom 元素指定触屏移动事件
hammertime.add(new Hammer.Pinch());
//添加事件
hammertime.on("pinchin", function (e) {
  document.getElementById("result").innerHTML += "捏合初触发<br />";
  //控制台输出
  console.log(e);
});

Press 事件

在指定的 dom 区域内触屏版本的点击事件,这个事件相当于 PC 端的 Click 事件,该不能包含任何的移动,最小按压时间为 500 毫秒,常用于我们在手机上用的“复制、粘贴”等功能。

  • Press:按压后触发
  • Pressup:按压离开时触发
<div id="test" class="test">事件区域</div>
<div id="result" class="result">事件结果:按压超过500ms触发<br /></div>
//创建一个新的hammer对象并且在初始化时指定要处理的dom元素
var hammertime = new Hammer(document.getElementById("test"));
//添加事件
hammertime.on("press", function (e) {
  document.getElementById("result").innerHTML += "超过500ms了<br />";
  //控制台输出
  console.log(e);
});

Pan 事件

在指定的 dom 区域内,一个手指放下并移动事件,即触屏中的拖动事件。这个事件在屏触开发中比较常用,如:左拖动、右拖动等,如手要上使用 QQ 时向右滑动出现功能菜单的效果。除了 Pan 事件以外,该事件还可以分别对以下事件进行监听并处理:

  • Panstart:拖动开始
  • Panmove:拖动过程
  • Panend:拖动结束
  • Pancancel:拖动取消
  • Panleft:向左拖动
  • Panright:向右拖动
  • Panup:向上拖动
  • Pandown:向下拖动

使用示例如下:

<div id="test" class="test">事件区域</div>
<div id="result" class="result">事件结果<br /></div>
//创建一个新的hammer对象并且在初始化时指定要处理的dom元素
var hammertime = new Hammer(document.getElementById("test"));
//添加事件
hammertime.on("pan", function (e) {
  document.getElementById("result").innerHTML += "X偏移量:【" + e.deltaX + "】,Y偏移量:【" + e.deltaY +
    "】<br />";
  //控制台输出
  console.log(e);
});

Tap 事件

在指定的 dom 区域内,一个手指轻拍或点击时触发该事件(类似 PC 端的 click)。该事件最大点击时间为 250 毫秒,如果超过 250 毫秒则按 Press 事件进行处理。

<div id="test" class="test">事件区域</div>
<div id="result" class="result">事件结果:点击触发<br /></div>
//创建一个新的hammer对象并且在初始化时指定要处理的dom元素
var hammertime = new Hammer(document.getElementById("test"));
//添加事件
hammertime.on("tap", function (e) {
  document.getElementById("result").innerHTML += "点击触发了,长按无效<br />";
  //控制台输出
  console.log(e);
});

Swipe 事件

在指定的 dom 区域内,一个手指快速的在触屏上滑动。即我们平时用到最多的滑动事件。

  • Swipe:下面所有滑动的集合
  • Swipeleft:向左滑动
  • Swiperight:向右滑动
  • Swipeup:向上滑动
  • Swipedown:向下滑动
<div id="test" class="test">事件区域</div>
<div id="result" class="result">事件结果:向左滑动触发<br /></div>
//创建一个新的hammer对象并且在初始化时指定要处理的dom元素
var hammertime = new Hammer(document.getElementById("test"));
//添加事件
hammertime.on("swipeleft", function (e) {
  document.getElementById("result").innerHTML += "X偏移量:【" + e.deltaX + "】,Y偏移量:【" + e.deltaY +
    "】<br />";
  //控制台输出
  console.log(e);
});