2

从 [长按] 开始学习 web 手势

在项目开发过程中遇到有虚拟键盘开发的需求(如下图),其中删除键需要实现 长按 删除输入框全部内容,由此展开今天要讨论的 web 手势 开发内容。

线下扫码

先放出实现代码:

var $input = document.getElementById('input');
var $delBtn = document.getElementById('delBtn');
var delBtnClock = null;
$delBtn.ontouchstart = function () {
    $input.innerHTML = $input.innerHTML.slice(0, -1)
    delBtnClock = setTimeout(function () {
        $input.innerHTML = '';
    }, 500);
}
$delBtn.ontouchend = function () {
    clearTimeout(delBtnClock);
    delBtnClock = null;
}

关键代码就两句话:

  1. 在 touchstart 事件中开启计时,这里是计时 500 ms 后,删除输入框内容
  2. 在 touchend 事件中清除 setTimeout 计时器

如果只是点击,此时 touchend 距离 touchstart 肯定不到 500 ms,计时器在时间没到前已被删除,实现的效果就只是退格;如果长按超过 500 ms,计时器执行,实现输入框内容全部删除。

所以 长按 手势实际上是由 touchstart & touchend & setTimeout 三者共同模拟的效果。

实际上,常规的 js 事件只支持 click、touchstart、touchend、touchmove、touchcancel 这五种与点击相关的事件,如果想实现更多的诸如旋转、放大缩小之类的手势的话,就需要结合上面的五种事件和其他方法来模拟实现了。

下面我将来介绍下传说中的《超级小的 web 手势库:AlloyFinger》

学习 AlloyFinger

业内知名的强大的 web 手势库 hammer.js,总共有 3240 行代码,压缩版的 44.7 kb。与之相比,AlloyFinger 真的称得上超级小了,326 行代码,10 倍的差距,在 “kb 必争” 移动 web 应用里,AlloyFinger 一下就引起了广大开发者的注意,代码量小,功能又齐全,你还要什么单车呢。(我是不是得找人家要下广告费)

在 AlloyFinger 里,手势一共有 14 种,除了常规的 4 种 touchstart,touchmove,touchend 和 touchcancel,还有 10 种由以上 4 种衍生出来的手势如下:

  • multipointStart:多点开始
  • multipointEnd:多点结束
  • tap:点击,效果如 click
  • doubleTap:双击
  • longTap:长按
  • singleTap:单击情况下 250 ms 内没有再次点击(会同时触发 tap,tap 在前)
  • rotate:旋转(同时触发 pressMove)
  • pinch:放大缩小
  • pressMove:单点移动
  • twoFingerPressMove:多点移动
  • swipe:扫滑,在 touchend 里触发,与 touchmove 稍有不同

原理

  1. multipointStart

    touchstart 中,触点多于 1 个时触发

  2. multipointEnd

    touchend 中,触点少于 2 个时触发(一开始还在想是不是 bug,实际的意思是:最后一个手指离开时触发)

  3. tap

    touchend 中,触点没有移动(移动横纵距离小于 30 px),且没有触发 longTap 时(距离 touchStart 时间少于 750 ms)触发

  4. doubleTap

    touchend 中,有上一次的点击记录 & 点击时间差小于 250 ms & 两次点击间没有移动(移动横纵距离小于 30 px)

  5. longTap

    touchstart 中,添加 750 ms 计时器,在这个时间段内没有松手(touchEnd)移动(touchMove),则触发

  6. singleTap

    touchend 中,单击情况下 250 ms 内没有再次点击

  7. rotate

    touchmove 中,触点多于 1 个,并存在上一次的多点移动记录时触发

  8. pinch

    touchmove 中,触点多于 1 个 & 存在上一次的移动记录 & 有缩放长度记录时触发

  9. pressMove

    touchmove 中,触点等于 1 个

  10. twoFingerPressMove

    touchmove 中,触点多于 1 个

  11. swipe

    touchend 中,触点有移动(移动横纵距离大于 30 px)

生命周期

重点

  1. 代码中多处使用 setTimeout(function () {}, 0);, 一方面实现同步转异步,释放线程,另一方面也能确保屏幕滚动时阻止事件的触发
  2. 滑动时,以最大的移动方向决定水平和竖直方向

    _swipeDirection: function (x1, x2, y1, y2) {
                return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
            }

在阅读源码过程中,对关键代码做了注释,点我


henry_chen
322 声望44 粉丝