如何准确获取移动端滑动时的瞬时速度?

UX-富水 阅读 411

我在做移动端图片轮播,想根据用户手指滑动的速度来决定是否自动翻页。但用 touchstart 和 touchend 算出来的速度总是不准,有时候轻轻一划反而触发了快速翻页。

我试过用时间差和位移计算速度,但感觉忽略了加速度或者中间的滑动轨迹。下面是我目前的简化代码:

const handleTouchEnd = (e) => {
  const endTime = Date.now();
  const deltaX = e.changedTouches[0].clientX - startX;
  const timeDiff = endTime - startTime;
  const velocity = Math.abs(deltaX / timeDiff); // 单位:px/ms
  if (velocity > 0.5) console.log('快速滑动');
};

这个 velocity 阈值调来调去都不稳定,是不是应该采样更多 touchmove 的点?有没有更靠谱的做法?

我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
Top丶晨羲
你这问题我也踩过坑,只算首尾两点肯定会翻车。用户手指滑到最后经常停顿一下再抬起来,这时候时间被拉长,速度就算废了。

正确的做法是采样 touchmove 的最后几个点,算瞬时速度才靠谱。复制这个:

let positions = [];

const handleTouchStart = (e) => {
positions = [];
positions.push({
x: e.touches[0].clientX,
time: Date.now()
});
};

const handleTouchMove = (e) => {
positions.push({
x: e.touches[0].clientX,
time: Date.now()
});
// 只保留最近100ms的数据点,太早的没用
const now = Date.now();
positions = positions.filter(p => now - p.time < 100);
};

const handleTouchEnd = (e) => {
if (positions.length < 2) return;

const first = positions[0];
const last = positions[positions.length - 1];
const deltaX = last.x - first.x;
const timeDiff = last.time - first.time;

// 防止除以0
if (timeDiff === 0) return;

const velocity = deltaX / timeDiff; // px/ms,正负代表方向

// 这个阈值自己调,0.3-0.5比较常见
if (Math.abs(velocity) > 0.3) {
console.log('快速滑动,方向:', velocity > 0 ? '右' : '左');
}
};


核心思路就是只看最近 100ms 内的滑动轨迹,这样不管用户最后停多久都不影响判断。positions 数组记得在 touchstart 时清空,不然会出 bug。

阈值 0.3 到 0.5 之间自己调,不同设备像素密度不一样,有条件的话可以用 devicePixelRatio 做个适配,不过一般直接调个大概值也够用了。
点赞
2026-03-01 17:03