transform translate仅生效一次:按W键小球无法持续上移求助
小球移动问题:transform仅生效一次的解决方案
我用以下代码实现小球移动功能,但transform: translate仅生效一次,尽管setInterval()在持续运行。按下W键后期望小球上移至屏幕顶部,但它只移动一次。
相关代码
HTML文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="MoveTheBall.css"> <title>Move the ball</title> </head> <body> <div class="ball"></div> <script src="MoveTheBall.js"></script> </body> </html>
CSS文件
.ball{ height: 5rem; width: 5rem; background-color: salmon; border-radius: 50%; position: relative; top: 35vw; left: 45vw; }
JavaScript文件
var ball = document.querySelector('.ball'); document.addEventListener('keypress' , function(event) { console.log('key', event.key); if(event.key === 'w') { moveUp(); } }); function moveUp() { let ballRect; let interval = setInterval(function() { ballRect = ball.getBoundingClientRect(); if(ballRect.top > 0) { ball.style.transform = 'translateY(-10px)'; } else { clearInterval(interval); } }, 300); }
问题原因
每次执行ball.style.transform = 'translateY(-10px)'时,都是将小球相对于初始位置向上移动10px,而不是在当前位置的基础上继续位移。所以第一次执行后,小球位置固定,后续重复设置相同的transform值不会产生新的位移。
解决方案
方案1:维护位移变量累加(推荐,性能更优)
通过变量记录当前的Y轴总位移,每次叠加偏移量,确保transform是基于初始位置的累计位移:
var ball = document.querySelector('.ball'); // 记录当前Y轴累计位移,初始为0 let currentYOffset = 0; document.addEventListener('keypress', function(event) { console.log('key', event.key); if(event.key === 'w') { moveUp(); } }); function moveUp() { let interval = setInterval(function() { const ballRect = ball.getBoundingClientRect(); if(ballRect.top > 0) { // 每次向上偏移10px currentYOffset -= 10; ball.style.transform = `translateY(${currentYOffset}px)`; } else { clearInterval(interval); } }, 300); }
方案2:直接修改top属性(逻辑更直观)
因为小球是position: relative定位,直接修改top属性,每次在当前值基础上减少10px:
var ball = document.querySelector('.ball'); document.addEventListener('keypress', function(event) { console.log('key', event.key); if(event.key === 'w') { moveUp(); } }); function moveUp() { let interval = setInterval(function() { const ballRect = ball.getBoundingClientRect(); if(ballRect.top > 0) { // 获取当前top值并转为数字,减去10px后重新设置 const currentTop = parseInt(window.getComputedStyle(ball).top); ball.style.top = `${currentTop - 10}px`; } else { clearInterval(interval); } }, 300); }
说明
- 方案1使用transform,不会触发浏览器重排,性能更好,适合动画场景。
- 方案2修改top属性会触发重排,但逻辑简单,适合对性能要求不高的场景。
内容的提问来源于stack exchange,提问作者Anoop Lamba
相关产品推荐
相关产品推荐

