记录手势使用

285 阅读2分钟

实现图片缩放和拖动功能

在Vue3项目里利用Hammer.js库实现图片缩放和拖动功能。可以在iPad设备实现缩放和拖动的手势。

准备工作

在开始之前,我们需要安装Hammer.js库。可以使用以下命令进行安装:

npm install  hammerjs

HTML模板

首先,我们需要在HTML模板中添加一个包含图片的div元素。图片的宽度和高度设置为100%以适应父元素的大小。代码如下:

<template>
  <div ref="image">
    <img :src="pictureSrc" style="width: 100%; height: 100%" />
  </div>
</template>

Vue组件

接下来,我们需要在Vue组件中编写代码来实现图片缩放和拖动功能。首先,我们需要导入所需的库和函数。然后,我们定义一些变量来保存图片的位置、缩放比例和上一次的位置和缩放比例。我们还获取设备屏幕的宽度和高度。

<script lang="ts">
import { ref, onMounted } from 'vue'
import Hammer from 'hammerjs'
import { storeToRefs } from 'pinia'
import { useStore } from '@/stores'
export default {
  setup() {
    const PcStore = useStore()
    const image = ref<HTMLImageElement | null>(null)
    let posX = 0
    let posY = 0
    let scale = 1
    let lastPosX = 0
    let lastPosY = 0
    let lastScale = 1

    // 获取设备屏幕的宽度和高度
    const screenWidth = document.body.clientWidth
    const screenHeight = document.body.clientHeight

    // ...
  }
}
</script>

然后,我们定义一个函数applyTransform来应用变换。在这个函数中,我们首先获取图片的宽度和高度,然后根据设备屏幕的宽度和高度计算出图片的最大和最小位置。接下来,我们检查图片的位置是否超出了边界

<script lang="ts">
// ...

function applyTransform() {
  if (image.value) {
    // 获取图片宽度和高度
    const imageWidth = image.value.clientWidth
    const imageHeight = image.value.clientHeight

    // 边界限制
    const maxPosX = 0
    const maxPosY = screenHeight - imageHeight
    const minPosX = -(screenWidth - imageWidth)
    const minPosY = 0
    // 超出边界处理
    if (posX > maxPosX) posX = maxPosX
    if (posX < minPosX) posX = minPosX
    if (posY > maxPosY) posY = maxPosY
    if (posY < minPosY) posY = minPosY

    const transformString = `translate(${posX}px, ${posY}px) scale(${scale})`
    image.value.style.transform = transformString
    image.value.style.webkitTransform = transformString
  }
}

// ...
</script>

接下来,我们在onMounted生命周期钩子中初始化Hammer.js,并添加所需的手势识别器。然后,我们在每个手势的事件处理程序中更新图片的位置和缩放比例,并调用applyTransform函数来应用变换。最后,我们在panendpinchend事件中更新上一次的位置和缩放比例。

<script lang="ts">
// ...

onMounted(() => {
  if (image.value) {
    const mc = new Hammer.Manager(image.value)

    mc.add(new Hammer.Pan({ threshold: 0, pointers: 0 }))
    mc.add(new Hammer.Swipe()).recognizeWith(mc.get('pan'))
    mc.add(new Hammer.Rotate({ threshold: 0 })).recognizeWith(mc.get('pan'))
    mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([mc.get('pan'), mc.get('rotate')])

    mc.on('panstart panmove', (e) => {
      posX = lastPosX + e.deltaX
      posY = lastPosY + e.deltaY
      applyTransform()
    })

    mc.on('pinchstart pinchmove', (e) => {
      scale = lastScale * e.scale
      applyTransform()
    })

    mc.on('panend', () => {
      lastPosX = posX
      lastPosY = posY
    })

    mc.on('pinchend', () => {
      lastScale = scale
    })
  }
})

// ...
</script>

最后,我们将图片元素和其他需要的数据返回给模板。这里我们使用了storeToRefs函数来将store中的数据转换为响应式的数据。

<script lang="ts">
// ...

return {
  image,
  ...storeToRefs(PcStore)
}

// ...
</script>