uniapp 摇杆
uniapp 实现虚拟摇杆的方法
在uniapp中实现虚拟摇杆功能,通常需要结合canvas绘制和触摸事件监听。以下是具体实现方案:
基础摇杆实现
-
创建canvas画布 在template中添加canvas元素,并设置宽高:
<canvas canvas-id="joystickCanvas" style="width: 300px; height: 300px;"></canvas> -
初始化摇杆 在onReady生命周期中初始化画布和摇杆位置:
onReady() { this.ctx = uni.createCanvasContext('joystickCanvas') this.drawJoystick(150, 150) // 初始位置居中 } -
绘制摇杆图形 使用canvas API绘制摇杆底座和可移动杆:
drawJoystick(x, y) { this.ctx.clearRect(0, 0, 300, 300) // 绘制底座 this.ctx.beginPath() this.ctx.arc(150, 150, 100, 0, 2 * Math.PI) this.ctx.fillStyle = 'rgba(0,0,0,0.2)' this.ctx.fill() // 绘制摇杆 this.ctx.beginPath() this.ctx.arc(x, y, 40, 0, 2 * Math.PI) this.ctx.fillStyle = 'rgba(255,255,255,0.8)' this.ctx.fill() this.ctx.draw() }
触摸事件处理
-
绑定触摸事件 在canvas元素上添加触摸事件绑定:
<canvas @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"></canvas> -
处理触摸开始 记录初始触摸位置:
onTouchStart(e) { this.touchStartX = e.touches[0].x this.touchStartY = e.touches[0].y this.updateJoystickPosition(e.touches[0].x, e.touches[0].y) } -
处理触摸移动 计算摇杆移动范围并限制在底座内:
onTouchMove(e) { const x = e.touches[0].x const y = e.touches[0].y // 计算与中心点的距离 const dx = x - 150 const dy = y - 150 const distance = Math.sqrt(dx * dx + dy * dy) // 限制在底座半径内 if (distance > 100) { const ratio = 100 / distance x = 150 + dx * ratio y = 150 + dy * ratio } this.updateJoystickPosition(x, y) } -
处理触摸结束 摇杆返回中心位置:
onTouchEnd() { this.drawJoystick(150, 150) // 可以触发停止事件 }
方向计算与事件触发
-
计算摇杆方向 根据摇杆位置计算方向向量:
getDirectionVector(x, y) { const dx = (x - 150) / 100 // 归一化到[-1,1] const dy = (y - 150) / 100 return { dx, dy } } -
触发方向事件 可以在onTouchMove中添加方向判断逻辑:
const { dx, dy } = this.getDirectionVector(x, y) if (dx > 0.5) { // 向右 } else if (dx < -0.5) { // 向左 } // 同理处理上下方向
性能优化建议
-
使用requestAnimationFrame优化绘制 避免频繁重绘,使用动画帧控制:
updateJoystickPosition(x, y) { if (!this.rafId) { this.rafId = requestAnimationFrame(() => { this.drawJoystick(x, y) this.rafId = null }) } } -
节流事件处理 对高频的touchmove事件进行节流:
let lastTime = 0 onTouchMove(e) { const now = Date.now() if (now - lastTime < 16) return // 约60fps lastTime = now // 正常处理逻辑 } -
预加载资源 提前加载摇杆图片资源(如果使用图片而非绘制):
onLoad() { uni.downloadFile({ url: 'https://example.com/joystick.png', success: (res) => { this.joystickImg = res.tempFilePath } }) }
跨平台兼容处理
-
处理H5和微信小程序差异 不同平台触摸事件坐标获取方式不同:
getTouchPosition(e) { #ifdef H5 return { x: e.touches[0].clientX, y: e.touches[0].clientY } #endif #ifdef MP-WEIXIN return { x: e.touches[0].x, y: e.touches[0].y } #endif } -
响应式布局 根据屏幕尺寸动态调整摇杆大小:
onLoad() { uni.getSystemInfo({ success: (res) => { this.screenWidth = res.windowWidth this.joystickSize = res.windowWidth * 0.3 } }) }
以上方案提供了在uniapp中实现虚拟摇杆的完整方法,可根据实际需求调整样式和交互细节。







