移动端触摸事件下图片触摸点居中拖动的实现问题
触摸拖动图片时touchstart阶段无法让中心对齐触摸点
需求
触摸拖动图片时,希望图片中心立刻与触摸点对齐(比如触摸图片右上角,图片自动移动使中心落在该触摸点)。目前touchmove功能正常,仅touchstart阶段存在该问题。
已尝试的无效代码
- 初始尝试:
img.style.left = e.touches[0].clientX +"px"; img.style.top = e.touches[0].clientX - shiftX +"px";
- touchstart完整代码:
img.addEventListener('touchstart', function(e) { beingDragged = img; start = e.target.parentNode.id; img.style.zIndex = 1; shiftX = e.touches[0].clientX-(img.width/2); shiftY = e.touches[0].clientY - (img.height/2);//code for dragging the image in the later touchmove event img.style.left = e.touches[0].clientX +"px"; img.style.top = e.touches[0].clientY +"px"; });
- 使用touchmove偏移值修复:
img.style.left = e.touches[0].clientX - shiftX +"px"; img.style.top = e.touches[0].clientY - shiftY +"px";
- 使用边界客户端矩形修复:
img.style.left = e.touches[0].clientX - img.getBoundingClientRect().left; img.style.top = e.touches[0].clientY - img.getBoundingClientRect().top;
图片CSS样式
img{ position: absolute; width: 90%; height: 90%; left: 50%; top: 50%; transform: translate(-50%, -50%); }
补充信息
制作Demo时问题解决,但移植到主代码后图片会飞出屏幕。Demo代码:
<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content=width=device-width,user-scalable=no> <meta charset="UTF-8"> </head> <body> <script> let shiftX; let shiftY; let img = document.createElement('img'); img.style.position = "absolute"; img.style.height = 99.016+"px"; img.addEventListener('touchstart', function(e) { start = e.target.parentNode.id; img.style.zIndex = 1; }); img.addEventListener("touchmove", function(e) { e.preventDefault(); img.style.left=e.touches[0].clientX-img.width/2+"px"; img.style.top=e.touches[0].clientY-img.height/2+"px"; }); document.body.appendChild(img); </script> </body> </html>
问题原因及解决方法
核心原因
主代码中图片使用了transform: translate(-50%, -50%)实现居中,这个属性只会改变元素的视觉位置,不会修改style.left/style.top的实际值,导致touchstart阶段的坐标计算出现偏差。而Demo中没有使用该transform属性,所以计算逻辑正常。
修复方案
方案1:移除transform居中,统一使用left/top定位
修改图片初始CSS,去掉transform,直接用margin实现居中:
img{ position: absolute; width: 90%; height: 90%; left: 0; top: 0; right: 0; bottom: 0; margin: auto; }
然后更新touchstart事件代码,直接让图片中心对齐触摸点:
img.addEventListener('touchstart', function(e) { beingDragged = img; start = e.target.parentNode.id; img.style.zIndex = 1; // 使用offsetWidth/offsetHeight获取渲染后的实际尺寸 const halfW = img.offsetWidth / 2; const halfH = img.offsetHeight / 2; // 设置中心对齐触摸点 img.style.left = e.touches[0].clientX - halfW + 'px'; img.style.top = e.touches[0].clientY - halfH + 'px'; // 重新计算touchmove需要的偏移值 shiftX = e.touches[0].clientX - img.offsetLeft; shiftY = e.touches[0].clientY - img.offsetTop; });
方案2:保留transform,但touchstart时重置它
如果必须保留初始的transform居中,在touchstart触发时先重置transform,避免干扰坐标计算:
img.addEventListener('touchstart', function(e) { beingDragged = img; start = e.target.parentNode.id; img.style.zIndex = 1; // 重置transform,消除对位置计算的干扰 img.style.transform = 'none'; const halfW = img.offsetWidth / 2; const halfH = img.offsetHeight / 2; // 设置中心对齐触摸点 img.style.left = e.touches[0].clientX - halfW + 'px'; img.style.top = e.touches[0].clientY - halfH + 'px'; // 更新偏移值 shiftX = e.touches[0].clientX - img.offsetLeft; shiftY = e.touches[0].clientY - img.offsetTop; });
关键注意点
- 不要使用
img.width/img.height,这两个值是图片的原始尺寸,而非渲染后的实际尺寸,改用offsetWidth/offsetHeight获取当前显示的尺寸。 - 确保touchmove中的位置计算逻辑和touchstart一致,避免出现拖动时的跳变。
内容的提问来源于stack exchange,提问作者Undefined
相关产品推荐
相关产品推荐

