移动端触摸事件需阻止默认行为、归一化坐标、主循环渲染,并按时间/位移/触点数识别tap/swipe/pinch;Phaser/Pixi中应代理原生touch事件,注意devicePixelRatio对齐及touchcancel清理。

移动端 touch 事件怎么绑定才不会丢手势
直接在 canvas 上监听 touchstart/touchmove/touchend 是基础,但容易漏掉快速滑动或连续多指操作。关键不是“加监听”,而是“防止默认行为干扰”和“统一事件坐标归一化”。
- 必须在
touchstart和touchmove中调用event.preventDefault(),否则 iOS Safari 会触发页面滚动/缩放,导致touchmove中断 - 用
getBoundingClientRect()计算canvas相对于视口的偏移,再减去event.touches[0].clientX/Y,才能得到准确的画布内坐标 - 避免在
touchmove里做重绘逻辑,只更新手势状态(如isDragging = true、lastX),把渲染交给主循环(requestAnimationFrame)
如何区分 tap、swipe、pinch 三种基本手势
靠单次事件无法判断,得靠时间 + 位移 + 触点数的组合阈值。HTML5 游戏引擎里不推荐用第三方库(如 Hammer.js)——体积大、与游戏帧率不同步、难以干预中间状态。
-
tap:
touchstart→touchend时间 Math.hypot(dx, dy) 算欧氏距离) -
swipe:
touchstart到touchend位移 > 50px,速度 > 0.3px/ms(用(endTime - startTime)算分母),方向由dx/dy符号决定 -
pinch:仅当
event.touches.length === 2时计算两指间距变化:scale = currentDistance / previousDistance;注意要缓存上一帧的touches,不能只依赖当前touchmove的快照
Phaser 3 或 PixiJS 里怎么接入自定义手势逻辑
别覆盖引擎内置的交互系统(比如 Phaser 的 input.enable),而是用“事件代理”方式注入。引擎本身对多点触控支持有限,尤其是 pinch 缩放,得自己接管底层 touch 流。
- 在初始化后立刻给
game.canvas绑定原生touchstart等事件,用game.canvas.addEventListener('touchstart', ...),而不是通过场景或容器加 - 把识别出的手势转成自定义事件抛给游戏逻辑:
game.events.emit('gesture:swipe', { direction: 'right', velocity: 1.2 }) - PixiJS 用户注意:
app.view默认有touchstart拦截,需设app.renderer.plugins.interaction.autoPreventDefault = false,否则你的touchstart拿不到事件
为什么 pinch 缩放总卡顿或错位
核心问题是坐标系没对齐:手势识别用的是 CSS 像素坐标,而 Canvas 渲染用的是设备像素(devicePixelRatio)。缩放中心点一旦算偏,视觉上就像“抖动”或“偏移”。
立即学习“前端免费学习笔记(深入)”;
- 缩放中心必须用两指中点的 canvas 坐标(已除过
devicePixelRatio),不是 client 坐标 - Canvas 的
style.width/height和canvas.width/height必须同步缩放:比如canvas.width = canvas.clientWidth * window.devicePixelRatio - 不要直接改
canvas.style.transform做缩放——它影响 hitTest,且与 Pixi/Phaser 的世界坐标系冲突;应把 scale 应用到游戏对象的scale.x/y上,并平移position补偿缩放中心偏移
实际项目里最常被忽略的是 touchcancel 事件处理——用户切后台、弹系统通知、接电话都会触发它,不清理拖拽状态会导致后续所有手势错乱。记得在 touchcancel 里重置所有 isXXXing 标志和缓存坐标。











