JavaScript中event.touches[1].clientX坐标偏移问题求助
解决多触摸场景下坐标偏移的问题
问题描述
代码包含3个可触摸交互的div元素,通过ee.touches[0]和ee.touches[1]获取触摸坐标时,先触摸botondisparoContenedor元素后,再触摸botonleftContenedor或botonrightContenedor会出现clientX坐标偏移,无法正常识别触摸操作。
问题根源
- 固定依赖触摸点的索引(
touches[0]/touches[1])判断触摸元素,但多触摸时触摸点的顺序会动态变化,导致拿错对应坐标。 - 通过
elementFromPoint反查元素的逻辑冗余且易出错,触摸事件本身可以直接通过event.target获取触发元素。 - 单个变量
tomaEstaDireccion被多个触摸操作覆盖,无法同时跟踪多个触摸状态。
解决方案
- 利用触摸事件的
identifier属性唯一标识每个触摸点,维护触摸点与元素的映射关系。 - 直接通过
event.target获取触发触摸的元素,无需通过坐标反查。 - 分离移动和射击的触摸状态,避免变量冲突。
修改后的完整代码
<style> .botonleftContenedor{ width:19vw; height:100vh; float:left; background-color: #00000090 } .botonrightContenedor{ width:19vw; height:100vh; float:left; background-color: #00000090 } .botondisparoContenedor{ width:19vw; height:100vh; float:right; background-color: #00000090 } .inicio{ width:90vw; height:10vh; } </style> <div id="botonleftContenedor" class="botonleftContenedor"></div> <div id="botonrightContenedor" class="botonrightContenedor"></div> <div id="botondisparoContenedor" class="botondisparoContenedor"></div> <div id="inicio" class="inicio"></div> <script> // 玩家状态 let actDireccion = 0; // 0 静止 / 1 向右 / 2 向左 let disparo = 0; let activadoDisp = 0; let iniciarDisparos; // 跟踪触摸点与元素的映射 const touchMap = new Map(); // 移动控制逻辑 function handleMovement(event) { const targetId = event.target.id; const touchId = event.type.includes('touch') ? event.changedTouches[0].identifier : 'mouse'; if (event.type === 'touchstart' || event.type === 'mousedown' || event.type === 'pointerdown') { touchMap.set(touchId, targetId); updateDirection(); } else if (event.type === 'touchend' || event.type === 'mouseup' || event.type === 'pointerup') { touchMap.delete(touchId); updateDirection(); } else if (event.type === 'touchmove') { // 触摸移动时更新坐标显示 const touch = event.changedTouches[0]; document.getElementById("inicio").innerHTML = `${touch.clientX} -- ${touch.clientY}`; } else if (event.type === 'keydown') { if (event.keyCode === 39) { actDireccion = 1; } else if (event.keyCode === 37) { actDireccion = 2; } } else if (event.type === 'keyup') { if (event.keyCode === 39 || event.keyCode === 37) { actDireccion = 0; } } } // 更新移动方向 function updateDirection() { const hasRight = Array.from(touchMap.values()).includes('botonrightContenedor'); const hasLeft = Array.from(touchMap.values()).includes('botonleftContenedor'); if (hasRight && !hasLeft) { actDireccion = 1; } else if (hasLeft && !hasRight) { actDireccion = 2; } else { actDireccion = 0; } } // 射击控制逻辑 function dispararAhoraa(event) { if ((event.keyCode === 32 || event.target.id === "botondisparoContenedor") && activadoDisp === 0) { disparo++; iniciarDisparos = setInterval(() => { disparo++; }, 20); activadoDisp = 1; } } function dejaDeDisparar(event){ if (event.keyCode === 32 || event.target.id === "botondisparoContenedor") { activadoDisp = 0; clearInterval(iniciarDisparos); } } // 绑定事件 const clickMoverRight = document.getElementById('botonrightContenedor'); const clickMoverLeft = document.getElementById('botonleftContenedor'); const clickdisparar = document.getElementById("botondisparoContenedor"); // 移动按钮事件 clickMoverRight.addEventListener("touchstart", handleMovement); clickMoverRight.addEventListener("touchend", handleMovement); clickMoverRight.addEventListener("touchmove", handleMovement); clickMoverLeft.addEventListener("touchstart", handleMovement); clickMoverLeft.addEventListener("touchend", handleMovement); clickMoverLeft.addEventListener("touchmove", handleMovement); // 射击按钮事件 clickdisparar.addEventListener("touchstart", dispararAhoraa); clickdisparar.addEventListener("touchend", dejaDeDisparar); // 键盘事件 document.addEventListener("keydown", handleMovement); document.addEventListener("keyup", handleMovement); document.addEventListener("keydown", dispararAhoraa); document.addEventListener("keyup", dejaDeDisparar); </script>
关键改进点
- 使用
touchMap跟踪每个触摸点对应的元素ID,避免多触摸时顺序错乱。 - 直接通过
event.target获取触发元素,无需坐标反查,彻底解决坐标偏移问题。 - 分离方向更新逻辑为单独函数,代码更清晰易维护。
- 增加
clearInterval清理定时器,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Donjode
相关产品推荐
相关产品推荐

