移动端捏合缩放手势怎么监听才靠谱?

Prog.子阳 阅读 16

我在做移动端图片预览功能,想支持双指捏合缩放,但 touchstart 和 touchmove 事件里判断距离变化总是不准,有时候还会和页面滚动冲突。

试过用 event.touches.length === 2 判断双指,然后算两点间距离,但缩放比例算出来很飘,而且偶尔会触发浏览器默认的页面缩放。有没有更稳的做法?

function handleTouchMove(e) {
  if (e.touches.length === 2) {
    const dx = e.touches[0].pageX - e.touches[1].pageX;
    const dy = e.touches[0].pageY - e.touches[1].pageY;
    const distance = Math.sqrt(dx * dx + dy * dy);
    // 然后拿 distance / initialDistance 当缩放比例...
  }
}
我来解答 赞 2 收藏
二维码
手机扫码查看
1 条解答
码农含平
别自己算距离了,直接用 gesturestart gesturechange gestureend 这三个手势事件,专为捏合缩放设计的,浏览器底层已经帮你处理了双指识别和缩放比例,比自己算稳定多了。

关键点就三步:

1. 在 gesturestart 里记录初始缩放比例(一般是1),并阻止默认行为防止浏览器自己缩放页面
2. 在 gesturechange 里直接用 event.scale 就是当前缩放倍数,拿它乘以初始值就行
3. 最后记得在 touchmove 里加个 e.preventDefault() 防止滚动干扰(只在双指时)

代码直接贴这个:

let initialScale = 1;
let isPinching = false;

element.addEventListener('gesturestart', (e) => {
if (e.touches.length === 2) {
e.preventDefault();
isPinching = true;
initialScale = currentScale || 1; // currentScale 是你当前图片的缩放值
}
});

element.addEventListener('gesturechange', (e) => {
if (!isPinching) return;
e.preventDefault();
const newScale = initialScale * e.scale;
applyScale(newScale); // 你自己的缩放逻辑
});

element.addEventListener('gestureend', (e) => {
if (isPinching) {
isPinching = false;
currentScale = initialScale * e.scale; // 保存当前缩放状态
}
});

// 同时在 touchmove 里防滚动(只针对双指)
element.addEventListener('touchmove', (e) => {
if (e.touches.length === 2) {
e.preventDefault();
}
}, { passive: false });


注意 passive: false 得加上,不然 preventDefault 不生效,滚动挡不住。

另外别忘了在 meta 里关掉浏览器默认缩放:



这样基本能覆盖主流安卓和iOS了,我线上项目就是这么用的,稳。
点赞
2026-02-26 14:20