changedTouches在移动触控中如何获取多个手指的坐标?

依诺 Dev 阅读 38

我在开发一个移动端绘画功能时遇到问题,当用户用多手指触控屏幕时,想通过changedTouches获取所有手指的坐标,但发现只能拿到最后一个手指的数据。比如用两个手指同时移动时,canvas上只显示一个点在移动,代码该怎么改?

我试过在touchmove事件里这样写:const x = event.changedTouches[0].clientX,但调试发现changedTouches数组长度有时是2,但取值总是最后一个触点的坐标。难道要遍历整个数组?或者应该用touches属性?

下面是事件处理的代码片段,但移动轨迹显示不正常:


function handleMove(event) {
  event.preventDefault();
  for(let i=0; i < event.changedTouches.length; i++) {
    const touch = event.changedTouches[i];
    ctx.lineTo(touch.clientX, touch.clientY);
    ctx.stroke();
  }
}

我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
诸葛松静
你遇到的问题其实挺常见的。用changedTouches获取多点触控坐标时,关键在于理解这个数组的更新机制。简单来说,changedTouches保存的是最近一次触发事件时发生变化的触点,但你在绘制的时候只做了lineTo,没有beginPath或者moveTo,导致每次只会画一个点,所以看起来像只有一个坐标在变化。

要解决这个问题,需要做这几件事:

1. 遍历changedTouches数组里的每个触点
2. 为每个触点创建独立的绘制路径
3. 注意不要把所有触点连在一起画成一条线

这是你原来的代码的问题所在:

function handleMove(event) {
event.preventDefault();
for(let i=0; i < event.changedTouches.length; i++) {
const touch = event.changedTouches[i];
ctx.lineTo(touch.clientX, touch.clientY); // 这里连续画线会导致轨迹混乱
ctx.stroke();
}
}


下面是修改后的建议写法:

function handleMove(event) {
event.preventDefault();

// 每个手指独立绘制
for(let i = 0; i < event.changedTouches.length; i++) {
const touch = event.changedTouches[i];

// 开始一个新的路径
ctx.beginPath();

// 把起点设为当前触点的位置
ctx.moveTo(touch.clientX, touch.clientY);

// 你可以在这里记录坐标,比如保存到数组中
// 或者直接画一个小圆点表示当前触点
ctx.arc(touch.clientX, touch.clientY, 5, 0, Math.PI * 2); // 画一个圆点
ctx.fill();
ctx.closePath();
}
}


如果你希望连续画线(比如两个手指都能留下轨迹),那就要保存每个触点的ID(identifier),跟踪它们的移动,并为每个触点维护一个独立的路径。这时候touches数组就派上用场了,因为它是当前所有在屏幕上的手指的列表。

举个例子,如果你要做两个手指各自画线的效果,可以这样处理:

const touchPaths = {}; // 保存每个触点的路径

function handleMove(event) {
event.preventDefault();

for(let i = 0; i < event.changedTouches.length; i++) {
const touch = event.changedTouches[i];
const id = touch.identifier; // 每个手指都有一个唯一的ID

if (!touchPaths[id]) {
// 如果是新的手指,初始化路径起点
touchPaths[id] = { x: touch.clientX, y: touch.clientY };
continue;
}

// 获取上一个位置,画线
const prev = touchPaths[id];
ctx.beginPath();
ctx.moveTo(prev.x, prev.y);
ctx.lineTo(touch.clientX, touch.clientY);
ctx.stroke();
ctx.closePath();

// 更新位置
touchPaths[id] = { x: touch.clientX, y: touch.clientY };
}
}


总结一下:

- changedTouches里保存的是本次事件中发生变化的触点
- 想要多个手指同时响应,就要遍历数组
- 每个触点要独立绘制,不要共享路径
- 需要保存触点的历史位置,用于连续画线
- touches和changedTouches都可以用,区别是touches是当前所有手指,changedTouches是这次事件中发生移动或新增的手指

这样修改后,你的canvas就能正常显示多个手指的轨迹了。我以前也踩过这个坑,确实容易理解错changedTouches的用途,特别是当你期望它保存所有手指位置的时候。
点赞 1
2026-02-08 11:28