移动端手势识别的核心基础
移动端手势识别的核心依赖触摸事件体系,浏览器提供了touchstart、touchmove、touchend三个核心触摸事件,分别对应手指接触屏幕、手指在屏幕移动、手指离开屏幕三个动作。我们可以通过监听这些事件,获取手指的位置、移动轨迹、时间间隔等信息,进而判断用户执行的手势类型。

触摸事件的核心属性
触摸事件的事件对象中包含TouchList类型的touches、changedTouches等属性,其中touches记录当前屏幕上所有触摸点的信息,changedTouches记录本次事件触发时状态发生变化的触摸点信息。每个触摸点对象包含clientX、clientY属性,代表触摸点在可视区域中的横纵坐标,这是我们计算手势轨迹的核心数据。
常见手势的实现逻辑
单击与双击手势
单击手势的判断逻辑是:手指触摸后短时间内没有移动,且快速离开屏幕。双击手势则是在单击的基础上,两次触摸的时间间隔小于指定阈值,且两次触摸的位置距离小于阈值。
下面是单击和双击手势的实现代码示例:
let lastTapTime = 0;
let lastTapX = 0;
let lastTapY = 0;
const tapDelay = 300; // 两次点击间隔阈值,单位毫秒
const tapDistance = 20; // 两次点击位置距离阈值,单位像素
document.addEventListener('touchstart', (e) => {
const touch = e.changedTouches[0];
const currentTime = Date.now();
const timeDiff = currentTime - lastTapTime;
const xDiff = Math.abs(touch.clientX - lastTapX);
const yDiff = Math.abs(touch.clientY - lastTapY);
if (timeDiff < tapDelay && xDiff < tapDistance && yDiff < tapDistance) {
console.log('触发双击手势');
lastTapTime = 0; // 重置时间,避免连续触发
} else {
// 记录本次触摸信息,等待下一次触摸判断是否为双击
lastTapTime = currentTime;
lastTapX = touch.clientX;
lastTapY = touch.clientY;
}
});
document.addEventListener('touchend', (e) => {
const touch = e.changedTouches[0];
const startTouch = e.target._startTouch;
if (!startTouch) return;
const moveX = Math.abs(touch.clientX - startTouch.clientX);
const moveY = Math.abs(touch.clientY - startTouch.clientY);
// 移动距离小于10像素判定为点击,避免滑动误判为点击
if (moveX < 10 && moveY < 10) {
const currentTime = Date.now();
const timeDiff = currentTime - lastTapTime;
if (timeDiff >= tapDelay) {
console.log('触发单击手势');
}
}
});
document.addEventListener('touchstart', (e) => {
const touch = e.changedTouches[0];
e.target._startTouch = {
clientX: touch.clientX,
clientY: touch.clientY,
time: Date.now()
};
}, true);
滑动手势
滑动手势需要判断手指移动的起点、终点、移动距离和方向,通常我们定义移动距离超过一定阈值(比如30像素)才判定为有效滑动,然后根据起点和终点的横纵坐标差值判断滑动方向是左、右、上、下。
滑动手势的实现代码如下:
document.addEventListener('touchstart', (e) => {
const touch = e.changedTouches[0];
e.target._swipeData = {
startX: touch.clientX,
startY: touch.clientY,
startTime: Date.now()
};
}, true);
document.addEventListener('touchend', (e) => {
const swipeData = e.target._swipeData;
if (!swipeData) return;
const touch = e.changedTouches[0];
const endX = touch.clientX;
const endY = touch.clientY;
const diffX = endX - swipeData.startX;
const diffY = endY - swipeData.startY;
const distance = Math.sqrt(diffX * diffX + diffY * diffY);
// 滑动距离小于30像素不判定为滑动
if (distance < 30) return;
const absDiffX = Math.abs(diffX);
const absDiffY = Math.abs(diffY);
if (absDiffX > absDiffY) {
// 横向滑动
if (diffX > 0) {
console.log('触发右滑手势');
} else {
console.log('触发左滑手势');
}
} else {
// 纵向滑动
if (diffY > 0) {
console.log('触发下滑手势');
} else {
console.log('触发上滑手势');
}
}
});
双指缩放手势
双指缩放需要监听两个触摸点的变化,通过计算两个触摸点之间的距离变化比例,判断是放大还是缩小操作。两个触摸点之间的距离可以通过勾股定理计算,距离变大为放大,距离变小为缩小。
双指缩放的实现代码如下:
let initialDistance = 0;
let scale = 1;
document.addEventListener('touchstart', (e) => {
if (e.touches.length === 2) {
// 两个触摸点,记录初始距离
const touch1 = e.touches[0];
const touch2 = e.touches[1];
const diffX = touch2.clientX - touch1.clientX;
const diffY = touch2.clientY - touch1.clientY;
initialDistance = Math.sqrt(diffX * diffX + diffY * diffY);
}
});
document.addEventListener('touchmove', (e) => {
if (e.touches.length === 2 && initialDistance > 0) {
e.preventDefault(); // 阻止默认滚动行为
const touch1 = e.touches[0];
const touch2 = e.touches[1];
const diffX = touch2.clientX - touch1.clientX;
const diffY = touch2.clientY - touch1.clientY;
const currentDistance = Math.sqrt(diffX * diffX + diffY * diffY);
scale = currentDistance / initialDistance;
if (scale > 1) {
console.log('触发放大手势,缩放比例:' + scale.toFixed(2));
} else if (scale < 1) {
console.log('触发缩小手势,缩放比例:' + scale.toFixed(2));
}
}
}, { passive: false });
document.addEventListener('touchend', (e) => {
if (e.touches.length < 2) {
// 手指离开,重置初始距离
initialDistance = 0;
scale = 1;
}
});
手势识别的注意事项
- 需要合理设置手势判定的阈值,比如点击的移动阈值、滑动的距离阈值、双击的时间阈值,避免不同手势之间出现误判。
- 多指手势操作时要注意触摸点的数量变化,及时重置相关状态,避免状态混乱。
- 部分浏览器中触摸事件的默认行为可能会影响手势判断,比如滚动、缩放,需要根据需求通过
preventDefault阻止默认行为,但要注意不要影响正常的页面交互。 - 复杂场景下可以将手势识别逻辑封装成独立的模块,方便在多个项目中复用,也便于后续扩展新的手势类型。
JavaScript手势识别移动端touch_event修改时间:2026-06-26 09:54:41