Vue 加 Hammer 处理手势

2020-01-27

This article is a bit old and the content may be outdated, so please refer to it with caution and remember to check the latest official materials (such as documentation, etc.)

接近原生 App 体验,手势是少不了的。但是无论是 Vue 还是 Vuetify 对手势的支持并不好,于是需要 Hammer.js 支持。

Hammer.js #

hammerjs 在拙劣的搜索之后,才发现了这个库。虽然有 一个 Vue 的封装库 vue-touch,但是它年久失修,而且其组件名称v-touch与 Vuetify 的某组件重名。。。

使用 #

http://hammerjs.github.io/

文档非常简单,提几点需要注意的地方

Vue 引用 DOM 元素 #

配合$ref食用更佳

<template>
  <div ref="container">
  </div>
</template>

<script>
export default {
  mounted() {
    let ele = this.$refs.container
  }
}
</script>
Vue

做主人 #

通过new Hammer(myElement, myOptions)创建的事件监听默认开启了tap, doubletap, press, horizontal panswipe,并且加上了禁用了的pinchrotate

所以使用new Hammer.Manager(myElement, myOptions)更加舒服。

理解get #

为什么用Hammer创建的对象可以随便get然后设置enable: false,而Hammer.Manager出来是null呢?

如上所述,Hammer创建的默认加上了全套事件监听,而Hammer.Manager出来是白板一块,自然不能get没有加入的事件了。

大坑一个 #

文档里的确说了pinchrotate会阻塞元素的事件响应,但没想到有点愚蠢和暴力:启用了pinch之后,scroll就不行了?!一个手指的滑动和两个手指的缩放有关系?

还好找到了解决方案:https://stackoverflow.com/a/27550784/8810271

由于hammerjs2.x 版本不允许绑定touchstart and touchend,可以直接绑 DOM 元素上啊!

于是解决如下:

<template>
  <div ref="container" class="container" @touchstart="touchStart" @touchend="touchEnd">
  </div>
</template>

<script>
import Hammer from 'hammerjs'
let originZoom
export default {
  mounted() {
    hammer = new Hammer.Manager(this.$refs.container)
    hammer.add(new Hammer.Swipe({ direction: Hammer.DIRECTION_HORIZONTAL }))
    hammer.add(new Hammer.Pinch({ enable: false }))
    hammer.on('pinchstart', this.pinchStart)
    hammer.on('pinchmove', this.pinchMove)
  },
  methods: {
    pinchStart(e) {
      originZoom = this.zoom
    },
    pinchMove(e) {
      this.zoom = originZoom * e.scale
    },
    touchStart(e) {
      if (e.touches.length > 1) {
        hammer.get('pinch').set({ enable: true })
      }
    },
    touchEnd(e) {
      hammer.get('pinch').set({ enable: false })
    }
  }
}
</script>
Vue
Leave your comments and reactions on GitHub