多点触控手势怎么监听 pinch 缩放?

迷人的国凤 阅读 60

我在做一个移动端图片查看器,想支持双指缩放,但不知道怎么正确监听 pinch 手势。试过 touchstart 和 touchmove,但自己算距离变化很麻烦,而且容易误触发。

看到有些库比如 Hammer.js 能直接用 pinch 事件,但项目不想引入额外依赖。有没有原生 JS 的简洁实现方式?

目前我这样写,但缩放时页面会抖动,而且两个手指移动不同步就失效了:

let startDistance = 0;
element.addEventListener('touchstart', (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;
    startDistance = Math.sqrt(dx * dx + dy * dy);
  }
});
element.addEventListener('touchmove', (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 currentDistance = Math.sqrt(dx * dx + dy * dy);
    const scale = currentDistance / startDistance;
    // 应用 scale 到图片...
  }
});
我来解答 赞 11 收藏
二维码
手机扫码查看
2 条解答
打工人雪瑞
嗯,我理解你的痛点。当时我也卡在这儿好几天,自己算距离确实容易出问题。你现在的代码有几个小问题:首先 touchmove 里没更新 startDistance,导致缩放计算不对;另外页面抖动是因为没阻止默认事件。

给你个改进版的实现:

let startDistance = 0;
let lastScale = 1;

element.addEventListener('touchstart', (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;
startDistance = Math.sqrt(dx * dx + dy * dy);
lastScale = 1; // 重置缩放比例
}
});

element.addEventListener('touchmove', (e) => {
if (e.touches.length === 2) {
e.preventDefault(); // 防止页面滚动
const dx = e.touches[0].pageX - e.touches[1].pageX;
const dy = e.touches[0].pageY - e.touches[1].pageY;
const currentDistance = Math.sqrt(dx * dx + dy * dy);

let scale = currentDistance / startDistance;
scale *= lastScale; // 累计缩放

// 应用 scale 到图片...

lastScale = scale; // 记住上次缩放值
}
});


这样写就流畅多了。记得在 touchend 的时候处理下边界条件,比如最小最大缩放范围啥的。这个方案虽然比不上 Hammer.js 那么完善,但至少能解决基本需求了。
点赞
2026-03-26 10:03
设计师培聪
搞定,试试这个:
let startDistance = 0, scale = 1;
element.addEventListener('touchstart', e => { if (e.touches.length == 2) startDistance = getDistance(e.touches); });
element.addEventListener('touchmove', e => { if (e.touches.length == 2) scale = getDistance(e.touches) / startDistance; });
function getDistance(touches) { let dx = touches[0].pageX - touches[1].pageX, dy = touches[0].pageY - touches[1].pageY; return Math.hypot(dx, dy); }
点赞
2026-03-23 00:03