处理 touch事件,hammer.js的使用

2019-03-28 by 杜宏伟

移动时代,处理touch事件变得尤为重要。 大家查查资料就知道,touch事件的兼容和手势处理还是很复杂的,所以一般情况下我们用 [hammerjs](http://hammerjs.github.io/) 来处理手势。

环境准备

hammer.js 下载地址

下载到本地,在页面中直接引用即可。

使用

hammer.js为了让大家方便使用,做了一套默认设置,然后用 new Hammer(myElement),就可以快速得到实例。不过,不建议大家用Manager的方式,多不了多少代码,但是灵活性会大大增加。

var mc = new Hammer.Manager(myElement, myOptions);

mc.add( new Hammer.Pan({ direction: Hammer.DIRECTION_ALL, threshold: 0 }) );
mc.add( new Hammer.Tap({ event: 'quadrupletap', taps: 4 }) );

mc.on("pan", handlePan);
mc.on("quadrupletap", handleTaps);

manager的方式初始化的实例默认是没有任何手势的,都需要手动添加,添加的时候可以自定义参数,这样就实现的个性化需求。

默认情况下,同一时刻,只能有一个手势得到响应。如果要同时响应,需要用到 recognizeWith

比如要响应signletap and doubletap

var mc = new Hammer.Manager(myElement);

mc.add( new Hammer.Tap({ event: 'doubletap', taps: 2 }) );
mc.add( new Hammer.Tap({ event: 'singletap' }) );

//在响应doubletap的同时响应singletap
mc.get('doubletap').recognizeWith('singletap');

mc.on("singletap doubletap", function(ev) {
    console.log( ev.type)
});

recognizeWith 表示同地识别,同时响应。当 doubletap的时候,会同时响应两次singletap,一次doubletap

如果没有recognizeWith,只会响应一次sigletap一次doubletap,因为连续两次tap被识别为doubletap,默认是只识别一个手势,所以不会响应singletap

如果想实现响应doubletap的时候不响应singletap,需要用到 requireFailure

var mc = new Hammer.Manager(myElement);

mc.add( new Hammer.Tap({ event: 'doubletap', taps: 2 }) );
mc.add( new Hammer.Tap({ event: 'singletap' }) );

//当响应doubletap失败时响应singletap,所以当doubletap的时候,就不会响应singletap了
mc.get('singletap').requireFailure('doubletap');

mc.on("singletap doubletap", function(ev) {
    console.log( ev.type)
});

默认有6种手势 pan,pinch,press,rotate,swipe,tap。其中 tap,press是没有位移的,其它的手势触点有位移。pan 和swipe都是拖动,但是pan手指不用离开,swipe需要有拖动,紧接离开的运作。

动态构建hammer实例

收到事件的时候,再构建实例,只添加特定的手势 比如 收到手势 tapLeft。这里有一个要注意的,就是在添加识别的时候,不是说手势一一对应的,比如 tap识别就包含了 tapleft,tapright,taptop,tapbottom。拿vue 的touch插件代码为例。


import Hammer from 'hammerjs'

const Component = {
  props: {
    tag: { type: String, default: 'div' }
  },
  mounted: function () {
    this.hammer = new Hammer.Manager(this.$el);
    this.setupRecognizers()
  },
  methods: {
    //只响应double tap事件
    tapdouble() {
      const that = this
      const gesture = 'tapdouble'
      that.hammer.add(new Hammer.Tap({ event: gesture, taps: '2' }))
      that.hammer.on(gesture, function (e) {
        return that.$emit(gesture, e);
      });
    },
    setupRecognizers() {
      var that = this;
      let buildInestures = ['tap', 'swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown',
        'pan',
        'panstart',
        'panmove',
        'panend',
        'pancancel',
        'panleft',
        'panright',
        'panup',
        'pandown']
      let keys = Object.keys(that._events)
      for (let i = 0; i < keys.length; i++) {
        const gesture = keys[i]
        if (buildInestures.indexOf(gesture) >= 0) {
          if (/^pan/.test(gesture)) {
            //默认是所有方向,最小移动距离10才会响应
            that.hammer.add(new Hammer.Pan())
          }
          if (/^tap/.test(gesture)) {
            //默认,最小press time 250ms,taps之前的间隔是300ms,识别两次tap的位置变化最小为10
            that.hammer.add(new Hammer.Tap())
          }
          if (/^swipe/.test(gesture)) {
            that.hammer.add(new Hammer.Swipe())
          }
          //只处理一个事件,也就是默认不会处理两个事件同时响应
          that.hammer.on(gesture, function (e) {
            return that.$emit(gesture, e);
          });
        }
        else {
          that[gesture]()
        }
      }

    },

    destroyed: function destroyed() {
      this.hammer.destroy();
    }
  },
  render: function render(h) {
    return h(this.tag || 'div', {}, this.$slots.default)
  }
}
export default {
  install(Vue) {
    const name = 'v-touch'
    Vue.component(name, Object.assign(Component, { name: name }));
  }
}

这个vue的touch插件默认只能实别内置的手势,和一个自定义手势 tapdouble,如果还需要自定义手势,直接按tapdouble的格式增加即可。因为能自定义,无论是recognizeWith,还是requireFailure都可以用。

Touch-action

有很多属性与touch有关,但Touch-action无疑是最重要的。chrome35+,IE10+都支持touch-action。这个属性告诉浏览器如何处理touch事件。用这个属性一般是用来阻止默认行为而不用写js代码。 详细说明 幸运的是,hammer.js会自动为我们添加合适的touch-action属性。

参考

我叫杜宏伟,前端开发。

一直想写博客,在2018的年的最后几天,终于上线了。

对于前端开发,一个特点就是太零散,很容易会了后面忘了前面,所以归纳总结很重要。再有就是分享,做前端好多年,以前都是看你们写的文章, 现在我也开始写一些,希望可以帮到入行的小伙伴。微信号 duhongwei5775

欢迎转载,只需注明作者,出处即可

版权说明:署名 4.0 国际(CC BY 4.0)