移动端事件基础

移动端有哪些事件

  1. PC 端的时候,已经接触过事件了,而到了移动端,又有了新的事件,分别为:

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

    <style>
      * {
        margin: 0;
        padding: 0;
      }
    
      .container {
        width: 200px;
        height: 200px;
        background-color: red;
      }
    </style>
    
    <div class="container"></div>
    
    <script>
      var box = document.querySelector('.container');
    
      box.addEventListener('touchstart', () => {
        console.log('手指按下去了');
      });
      box.addEventListener('touchmove', () => {
        console.log('手指滑动了');
      });
      box.addEventListener('touchend', () => {
        console.log('手指抬起了');
      });
    </script>
    

事件对象

  1. 通过事件对象,可以获取到本次事件发生时,一些更加具体的信息,例如:

    box.addEventListener('touchstart', (e) => {
      console.log(e);
    });
    
  2. 此时打印传入的事件对象,可以看到如下的信息:

  3. 可以看到,事件对象中一如既往的包含了很多信息,其中对于开发来讲比较重要的就是如下 3 个信息:都是 TouchList(手指列表)

    • changedTouches:触发当前事件的手指列表,也就是涉及当前(引发)事件的触摸点的列表
    • targetTouches:位于当前 DOM 元素上的手指列表,也就是当前对象上所有触摸点的列表
    • touches:位于当前屏幕上的所有手指列表(必需至少有 1 个手指在添加触发事件的元素上),也就是当前屏幕上所有触摸点的列表
  4. 通过一个例子来区分一下触摸事件中的这三个属性:

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

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

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

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

    • 早在 2007 年初,苹果公司在发布首款 iPhone 前夕,遇到一个问题:当时的网站都是为大屏幕设备所设计的,于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题;
    • 这当中最出名的,当属双击缩放( double tap to zoom ),这也是会有上述 300 毫秒延迟的主要原因;
    • 双击缩放,顾名思义,即用手指在屏幕上快速点击两次,ios 自带的 Safari 浏览器会将网页缩放至原始比例;那么这和 300 毫秒延迟有什么联系呢?
    • 假定这么一个场景: 用户在 ios Safari 里边点击了一个链接,由于用户可以进行双击缩放或者双击滚动的操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作;因此,ios Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕;
    • 鉴于 iPhone 的成功,其他移动浏览器都复制了 iPhone Safari 浏览器的多数约定,包括双击缩放,几乎现在所有的移动端浏览器都有这个功能;
  3. 下面看一下这个问题

    var box = document.querySelector('.container');
    
    box.addEventListener('click', () => {
      console.log('click 事件触发');
    });
    box.addEventListener('touchstart', () => {
      console.log('touchstart 事件触发');
    });
    
    // 点击后输出,没有了 300ms 的问题
    // touchstart 事件触发
    // click 事件触发
    

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

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

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

触发点区别

  1. PC 端

    • mousemove:不需要鼠标按下,但是必需在元素上才能触发
    • mouseup:必需在元素上抬起才能触发
  2. 移动端

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

触发顺序

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

  2. PC 的事件在移动端里会有 300ms左右 延迟(只要定义了 viewport 就不会有 300ms 延迟问题)

touchstart 与 click 的区别

  1. touchstart 手指碰到元素就触发

  2. click 手指碰到元素并且抬起才会触发

事件穿透

所谓事件穿透,是移动端上面一个非常有名的 Bug

其出现场景为:有两层重叠的元素,上面的元素有 touch 事件(点击后要消失),下面是一个默认会触发 click 事件的元素(a、表单元素、带 click 事件的元素),此时点击上一层的元素,下一层也同样会被点击;

  1. 来看一个例子:

    <style>
      * {
        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;
      }
    </style>
    
    <a href="http://www.baidu.com/">度娘</a><br>
    <input type="text">
    <p>这是一个段落</p>
    <div class="container"></div>
    
    <script>
      var box = document.querySelector('.container');
      box.addEventListener('touchstart', () => {
        box.style.display = 'none';
      });
      
      const p = document.querySelector('p');
      p.addEventListener('click', () => {
        alert('该段落被点击了');
      });
    </script>
    
  2. 为什么会存在事件穿透呢?

    • 这是因为在移动端浏览器,事件执行的顺序是 touchstarttouchmovetouchedclick
    • click 事件有 300ms 的延迟,当 touchstart 事件把上层元素隐藏之后,隔了 300ms,浏览器触发了 click 事件,但是此时上层元素不见了,所以该事件被派发到了下层元素身上;
  3. 那么既然存在这个问题,该如何解决呢?

    • 有一个最简单的解决方式,那就是取消事件的默认行为,如下:
      box.addEventListener('touchstart', ev => {
        box.style.display = 'none';
        ev.preventDefault(); // 取消事件的默认动作
      });
      
    • 当阻止了 touchstart 事件的默认行为后,事件穿透也就随即消失;

阻止默认行为带来的影响

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

  • 利用这个思想可以通过在 document 身上取消默认事件,从而阻止所有的默认事件;

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

touchmove

  • 阻止了浏览器的滚动条

  • 阻止了用户双指缩放

touchstart

  • 解决 IOS10+ 及部分安卓机通过设置 viewport 禁止用户缩放的功能(双指滑动、双击)

  • 解决事件点透问题

  • 阻止图片文字被选中

  • 阻止了长按元素会弹出系统菜单

  • 阻止了浏览器回弹的效果

  • 阻止了浏览器的滚动条

  • 阻止了鼠标的事件

  • 阻止了 input 框的输入功能

  1. 通过下面的例子看到部分功能已经失效:

    <style>
      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;
      }
    </style>
    
    <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>
    
    <script>
      const page = document.querySelector('.page');
      page.addEventListener('touchstart', ev => {
        ev.preventDefault();
      });
    </script>
    
  2. 另外,如果在 document 上面阻止默认事件,例如将上面的 JavaScript 修改如下:

    document.addEventListener('touchstart',ev=>{
        ev.preventDefault();
    });
    
  3. 会发现在 chrome 移动端模拟器或者手机浏览器上事件的默认行为并没有成功阻止,其中 preventDefault 不生效问题就是由 passive 这个参数引起的;

    tartget.addEventListener(type, listener, {
      capture: Booolean,
      once: Boolean,
      passive: Boolean,
      signal: AbortSignal
    })
    
  4. 为什么呢?

    • 事件监听器在监听事件时,并不能提前知道回调函数中是否会阻止默认行为,因此若想知道是否会阻止就需要等待函数执行完,这段时间虽然很短,但等待仍会让人感到卡顿;
    • 于是可以通过传递 passivetrue 来明确告诉浏览器,事件处理程序不会调用 preventDefault 来阻止默认滑动行为,而大部分事件监听器是不会阻止默认行为的,因此某些浏览器就将一些节点(例如 document)事件的 passive 默认设置为为 true
    • 因此要解决上面 document 上无法阻止默认行为的情况,只需要将 passive 设置为 false 即可,即明确告诉浏览器,事件处理程序会调用 preventDefault 来阻止默认滑动行为;
      document.addEventListener('touchstart', ev => {
         ev.preventDefault();
      }, { passive: false });
      
  5. 回到之前的话题,在父元素上面阻止元素默认行为,会导致很多元素的默认行为也没有了,那么此时该怎么办呢?

    • 比如在获取验证码时,通常用户希望验证码是能够复制的,因此会触发长按复制的默认事件,这个事件我们希望在这个元素身上不被阻止掉,那么应该如何实现?
    • 有一种方案是阻止冒泡,如上面所述,是通过冒泡来借助父元素阻止掉默认事件,那么如果切断冒泡,那么父元素身上的阻止默认事件就无法被触发,元素本身的默认事件就无法被阻止掉了;但是这样也只是解决了其中一个问题,上面还罗列出了很多其他问题,例如所有的滚动条失效,这些问题该怎么解决呢?
    • 实际上,移动端进行开发时一上来就需要阻止所有的默认事件,后面的很多功能都需要自定义来实现

滑屏操作与轮播图

滑屏操作

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

  • 这里就来实现一个滑屏操作;

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

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

    关于 Touch 对象各属性的含义,可以参阅 MDN

  2. 示例代码:

    • 因为滑屏操作涉及到频繁的滑动,而以前传统的通过 position 的方式来实现的话,会有重绘重排的性能问题,因此选择使用 CSS3transform 来实现滑动效果,CSS3 新增的 transform 有硬件加速等特性,性能上面要比传统的 position 要好一些;
    • 另外,在上面的代码中,用到了一个第三方库 Transform
    • 附件下载
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            body {
                margin: 0;
                padding: 0;
            }
    
            ul {
                list-style: none;
            }
    
            #wrap {
                height: 100vh;
                overflow: hidden;
                border: 5px solid red;
                box-sizing: border-box;
            }
            #list{
                transition: .4s;
            }
        </style>
    </head>
    
    <body>
        <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>
                <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>
        <script src="./transform.js"></script>
        <script>
            // 手动实现滑动效果
            // 获取 DOM 元素
            var wrap = document.querySelector("#wrap"); // 外层的 div
            var list = document.querySelector("#list");; // 里面的 ul
            var startPointY = 0, // 手指按下时的 Y 坐标
                startTop = 0, // 要滑动的元素默认的 top 值
                movePointY = 0; // 手指移动时的坐标
            // 这里我们用到了腾讯的第三方库 transform,通过 Transform(DOM节点) 进行一个初始化
            // 之后我们就可以非常方便的获取以及设置该 DOM 节点和 transform 相关的属性值
            Transform(list);
            console.log(list.translateY);
            wrap.addEventListener('touchstart', ev => {
                startPointY = ev.changedTouches[0].pageY; // 手指按下时的坐标
                startTop = list.translateY; // list 元素垂直轴移动的距离
            })
            wrap.addEventListener('touchmove', ev=>{
                // 坐标移动的距离 = 当前的距离 - 按下时的距离
                movePointY = ev.changedTouches[0].pageY - startPointY;
                // 元素移动的距离 = 按下时元素的 top + 坐标移动的距离
                list.translateY = startTop + movePointY;
            })
            document.addEventListener('touchstart',ev=>{
                ev.preventDefault();
            }, {
                passive : false
            })
        </script>
    </body>
    
    </html>
    

轮播图

  1. 接下来在滑屏操作上更进一步,来实现一个轮播图,其原理如下图所示:

  2. 代码如下:附件下载

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>轮播图</title>
        <style>
            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;
            }
        </style>
    </head>
    
    <body>
        <section id="banner">
            <!-- 轮播图 -->
            <div class="wrap">
                <a href="#"><img src="./img/banner_01.jpg" alt=""></a>
                <a href="#"><img src="./img/banner_02.jpg" alt=""></a>
                <a href="#"><img src="./img/banner_03.jpg" alt=""></a>
            </div>
            <!-- 小圆点 -->
            <div class="circle">
                <span class="active"></span>
                <span></span>
                <span></span>
            </div>
        </section>
        <script src="./transform.js"></script>
        <script>
            // 获取一些 DOM 节点
            var banner = document.querySelector("#banner"); // 最外层容器
            var wrap = document.querySelector(".wrap"); // 轮播图图片容器
            var spans = document.querySelectorAll(".circle span"); // 获取所用的小圆点
    
            // 初始化一些变量
            var imgWidth = banner.offsetWidth; // 一张图片的宽度
            var startPointX = 0; // 手指按下时的坐标
            var disPointX = 0; // 手指移动的距离
            var startEleX = 0; // 按下时元素的位置
            var cn = 0; // 当前图片的索引值
            var 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; // 记录手指按下去的时候的 X 坐标
    
                // 需要判断当前是第几张图,如果是第一张或者是最后一张,那么我们是要做特殊处理的
                // 因为我们并不知道用户是往左边还是右边,所以我们针对第一张和最后一张直接进行跳转
                if (cn === 0) {
                    cn = wrap.children.length / 2;
                }
    
                if (cn === wrap.children.length - 1) {
                    cn = wrap.children.length / 2 - 1;
                }
    
                wrap.style.transition = ""; // 去除 wrap 的过渡,否则一会儿拖动的时候就会因为过渡感觉慢半拍
                // 因为现在图片的下标已经更新了,所以我们需要根据新的下标修正 wrap 的 translate 移动距离
                wrap.translateX = - imgWidth * cn;
                // 还需要更新一下元素的移动距离
                startEleX = wrap.translateX;
                ev.preventDefault();
            });
    
            // 手指移动的时候要做的事情
            banner.addEventListener("touchmove", ev => {
                disPointX = ev.changedTouches[0].pageX - startPointX; // 获取手指移动的距离
                wrap.translateX = startEleX + disPointX;
            });
    
            // 手指抬起的时候要做的事情
            banner.addEventListener("touchend", ev => {
                // 当用户手指抬起的时候,需要判断要不要切换图片
                // 这个就根据用户手指移动的距离,如果用户手指移动的距离很短,我们就回弹图片
                // 我们将整个图片宽度分为 8 份,如果用户手指移动的距离大于八分之一,我们就切换,否则我们就回弹
                var backWidth = imgWidth / 8;
    
                if (Math.abs(disPointX) > backWidth) {
                    // 大于八分之一,那我们就切换图片
                    // 分为往左还是往右
                    if (disPointX < 0) {
                        // 往左边拖,想看下一张图片
                        cn++
                    }
                    if (disPointX > 0) {
                        // 往右边拖,想看上一张图片
                        cn--;
                    }
                }
                // 至此,图片的下标已经更新
                wrap.style.transition = ".3s";
                wrap.translateX = - imgWidth * cn;
    
                // 最后一个事情,就是更新小圆点
                // 这里还是根据图片的下标来做
                // 首先去除上一次圆点身上的 class
                spans[ln].className = "";
                // 给当前的下标添加上 class
                // 图片当前的索引:0 1 2 3 4 5 ==> 0 1 2 0 1 2
                spans[cn % (wrap.children.length / 2)].className = "active";
                // 更新上一个索引
                ln = cn % (wrap.children.length / 2)
            })
        </script>
    </body>
    
    </html>
    

移动端第三方库

Swiper.js 轮播图库

  • 有一些比较成熟的库,可以提升开发效率;

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

移动端手势库

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

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

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 移动端事件基础
    1. 1.1. 移动端有哪些事件
    2. 1.2. 事件对象
    3. 1.3. 移动端事件和 PC 端事件区别
      1. 1.3.1. 触发点区别
      2. 1.3.2. 触发顺序
      3. 1.3.3. touchstart 与 click 的区别
    4. 1.4. 事件穿透
    5. 1.5. 阻止默认行为带来的影响
      1. 1.5.1. touchmove
      2. 1.5.2. touchstart
  2. 2. 滑屏操作与轮播图
    1. 2.1. 滑屏操作
    2. 2.2. 轮播图
  3. 3. 移动端第三方库
    1. 3.1. Swiper.js 轮播图库
    2. 3.2. 移动端手势库