一、触摸事件基础:从手指按下到事件触发
触摸事件,说白了就是浏览器告诉你「用户的手指在屏幕上干了什么」。我刚开始做移动端开发时,总觉得触摸事件跟鼠标事件差不多,结果第一个项目就踩了坑——页面滚动卡顿、点击穿透、延迟响应……嗯,后来我才明白,触摸事件有它自己的一套规则。
这一章我们先打好地基。把触摸事件的类型、对象属性、坐标获取这三个核心点吃透,后面的延迟排查才能有的放矢。
1.1 触摸事件类型:三个核心兄弟
触摸事件主要有三个:touchstart、touchmove、touchend。它们对应手指的三个动作:按下、移动、抬起。
核心记忆点:触摸事件的生命周期就是「按下 → 移动(可选)→ 抬起」。任何触摸交互都逃不出这个模型。
| 事件类型 | 触发时机 | 典型场景 |
|---|---|---|
touchstart |
手指刚接触屏幕 | 开始拖拽、开始缩放 |
touchmove |
手指在屏幕上滑动 | 滚动列表、拖拽元素 |
touchend |
手指离开屏幕 | 确认点击、结束拖拽 |
我个人习惯在 touchstart 里记录起始坐标,在 touchmove 里计算偏移量,在 touchend 里做最终判断。这样逻辑清晰,不容易乱。
注意:还有一个 touchcancel 事件,当触摸被系统中断时触发(比如来电、弹窗)。很多新手会忽略它,导致状态没重置。我曾经在一个手势库中漏掉了 touchcancel,结果用户接电话回来,页面上的拖拽元素就「粘」在手指上了……
1.2 触摸事件对象:藏在 event 里的秘密
每个触摸事件都会带一个 TouchEvent 对象。它里面有三个重要的触摸点列表:
touches:当前屏幕上所有手指的列表targetTouches:在当前元素上的手指列表changedTouches:引起事件变化的手指列表
这三个列表有什么区别?我刚开始也搞混过。举个例子:
- 你用两根手指同时触摸屏幕,
touches里有 2 个点 - 如果只有一根手指碰到了按钮,
targetTouches只有 1 个点 - 当手指抬起时,
changedTouches记录的是「离开」的那根手指
实战建议:在 touchstart 和 touchmove 中,优先用 targetTouches;在 touchend 中,必须用 changedTouches。因为手指抬起后,它已经不在 touches 里了。
每个触摸点(Touch 对象)还包含这些关键属性:
| 属性 | 含义 | 单位 |
|---|---|---|
clientX / clientY |
触摸点相对于视口的坐标 | px |
pageX / pageY |
触摸点相对于整个页面的坐标 | px |
screenX / screenY |
触摸点相对于屏幕的坐标 | px |
radiusX / radiusY |
触摸点的椭圆半径 | px |
force |
触摸压力(3D Touch 设备) | 0~1 |
你想想看,clientX 和 pageX 有什么区别?说白了,clientX 是「你看到的位置」,pageX 是「文档实际的位置」。如果页面没有滚动,两者相等;如果滚动了,pageX 会更大。
1.3 触摸点坐标获取:代码怎么写
直接上代码。这是我常用的坐标获取模板:
element.addEventListener('touchstart', function(e) {
// 阻止默认行为,避免页面滚动干扰
e.preventDefault();
// 获取第一个触摸点
var touch = e.targetTouches[0];
// 记录起始坐标
var startX = touch.pageX;
var startY = touch.pageY;
console.log('触摸开始于:', startX, startY);
});
element.addEventListener('touchmove', function(e) {
e.preventDefault();
var touch = e.targetTouches[0];
var moveX = touch.pageX;
var moveY = touch.pageY;
// 计算偏移量
var deltaX = moveX - startX;
var deltaY = moveY - startY;
console.log('偏移量:', deltaX, deltaY);
});
element.addEventListener('touchend', function(e) {
// 注意:这里必须用 changedTouches
var touch = e.changedTouches[0];
var endX = touch.pageX;
var endY = touch.pageY;
console.log('触摸结束于:', endX, endY);
});
避坑指南:我曾经在 touchend 里用了 e.touches,结果死活拿不到坐标。后来才发现,手指都抬起来了,touches 列表已经空了。记住:touchend 里只用 changedTouches。
1.4 知识体系总览
下面这张图把本章的核心知识点串起来了。你可以把它当作触摸事件排查的「地图」:
1.5 本章小结
触摸事件的基础就这些。记住三个要点:
- 事件类型:
start→move→end,生命周期要清晰 - 触摸点列表:分清
touches、targetTouches、changedTouches - 坐标获取:
pageX/pageY最稳定,touchend用changedTouches