实现图片缩放和拖动功能
在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
函数来应用变换。最后,我们在panend
和pinchend
事件中更新上一次的位置和缩放比例。
<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>