UniApp手势魔法:打造跨平台高级手势识别系统
一、架构设计
基于Touch事件+数学算法的手势引擎,支持8种常见手势,兼容H5/小程序/APP三端
二、核心实现
1. 手势识别基础
// gesture.js
export default {
data() {
return {
startX: 0,
startY: 0,
startTime: 0,
gestureType: ''
}
},
methods: {
handleTouchStart(e) {
this.startX = e.touches[0].clientX
this.startY = e.touches[0].clientY
this.startTime = Date.now()
},
handleTouchEnd(e) {
const endX = e.changedTouches[0].clientX
const endY = e.changedTouches[0].clientY
const deltaX = endX - this.startX
const deltaY = endY - this.startY
const duration = Date.now() - this.startTime
this.recognizeGesture(deltaX, deltaY, duration)
},
recognizeGesture(dx, dy, duration) {
const absX = Math.abs(dx)
const absY = Math.abs(dy)
if (duration 50 && absY 0 ? 'swiperight' : 'swipeleft'
}
else if (duration 50 && absX 0 ? 'swipedown' : 'swipeup'
}
else if (duration > 500 && absX < 10 && absY < 10) {
this.gestureType = 'longpress'
}
// 更多手势判断...
this.triggerGestureEvent()
}
}
}
2. 手势事件分发
// gesture.js (续)
methods: {
triggerGestureEvent() {
switch(this.gestureType) {
case 'swipeleft':
this.$emit('swipeleft')
break
case 'swiperight':
this.$emit('swiperight')
break
case 'pinch':
this.$emit('pinch', this.scale)
break
// 其他手势事件...
}
},
// 双指缩放识别
handleTouchMove(e) {
if (e.touches.length === 2) {
const touch1 = e.touches[0]
const touch2 = e.touches[1]
const distance = this.getDistance(
touch1.clientX, touch1.clientY,
touch2.clientX, touch2.clientY
)
if (!this.initialDistance) {
this.initialDistance = distance
}
this.scale = distance / this.initialDistance
this.gestureType = 'pinch'
}
},
getDistance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
}
}
三、高级特性
1. 平台差异处理
/* #ifdef MP-WEIXIN */
// 小程序特殊处理
handleTouchStart(e) {
this.startX = e.touches[0].x
this.startY = e.touches[0].y
// 微信小程序touch事件坐标字段不同
}
/* #endif */
/* #ifdef H5 */
// H5添加被动事件监听
mounted() {
this.$el.addEventListener('touchmove',
this.handleTouchMove,
{ passive: true })
}
/* #endif */
/* #ifdef APP-NVUE */
// Native环境使用bindingx
const bindingx = uni.requireNativePlugin('bindingx')
bindPinch() {
bindingx.bind({
eventType: 'pan',
props: [
{
element: this.$refs.container,
property: 'transform.scale',
expression: 'x/100'
}
]
})
}
/* #endif */
2. 性能优化方案
// 节流处理
const throttle = (fn, delay) => {
let lastTime = 0
return function() {
const now = Date.now()
if (now - lastTime >= delay) {
fn.apply(this, arguments)
lastTime = now
}
}
}
// 使用
handleTouchMove: throttle(function(e) {
// 手势处理逻辑
}, 16), // 60fps
// 内存优化
beforeDestroy() {
/* #ifdef H5 */
this.$el.removeEventListener('touchmove', this.handleTouchMove)
/* #endif */
}
四、完整案例
<template>
<view
class="gesture-container"
@touchstart="handleTouchStart"
@touchend="handleTouchEnd"
@touchmove="handleTouchMove"
@touchcancel="handleTouchEnd">
<text v-if="gestureType">当前手势: {{gestureType}}</text>
<view
v-if="scale"
class="scale-display">
缩放比例: {{scale.toFixed(2)}}
</view>
</view>
</template>
<script>
import gestureMixin from '@/mixins/gesture.js'
export default {
mixins: [gestureMixin],
data() {
return {
scale: 1
}
},
methods: {
// 自定义手势处理
onSwipeLeft() {
uni.showToast({ title: '向左滑动' })
},
onPinch(scale) {
this.scale = scale
}
}
}
</script>
<style>
.gesture-container {
width: 100%;
height: 300px;
background-color: #f0f0f0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>