如何让Div保持移动后位置实现连续位移与位置交换?
解决Div连续随机移动并保持位置的问题
问题出在CSS animation 的机制上:动画定义的是从元素初始状态到目标状态的过渡,即使设置了 animation-fill-mode: forwards,当你再次添加同一个(或新的)动画时,浏览器依然会以元素的原始位置作为动画的起始点,导致元素跳回初始位置。
要实现连续移动并保持当前位置,核心是用JS跟踪元素的当前偏移量,每次移动都基于这个偏移量计算新位置,而非依赖CSS动画的初始状态。下面提供两种可行方案:
方案1:用CSS Transition + JS 跟踪位置
这种方式简单易实现,利用CSS过渡实现平滑移动,JS负责记录和更新当前位置。
HTML
<div class="container"> <div class="box" id="box1"></div> <div class="box" id="box2"></div> </div>
CSS
.container { position: relative; width: 600px; height: 400px; border: 1px solid #ccc; } .box { position: absolute; width: 80px; height: 80px; border-radius: 4px; /* 开启过渡,让位置变化平滑 */ transition: transform 0.5s ease; } #box1 { background: #4285F4; left: 0; top: 0; } #box2 { background: #EA4335; right: 0; top: 0; }
JS
// 存储每个盒子的当前偏移量(初始为0,因为初始位置是left/top设置的) const boxPositions = { box1: { x: 0, y: 0 }, box2: { x: 0, y: 0 } }; // 随机移动单个盒子 function moveRandom(boxId) { const box = document.getElementById(boxId); const currentPos = boxPositions[boxId]; // 生成随机偏移(基于当前位置,范围±100px) const deltaX = Math.floor(Math.random() * 200) - 100; const deltaY = Math.floor(Math.random() * 200) - 100; // 计算新位置 const newX = currentPos.x + deltaX; const newY = currentPos.y + deltaY; // 更新transform box.style.transform = `translate(${newX}px, ${newY}px)`; // 记录新位置 boxPositions[boxId] = { x: newX, y: newY }; } // 交换两个盒子的位置 function swapBoxes() { const box1 = document.getElementById('box1'); const box2 = document.getElementById('box2'); const pos1 = boxPositions.box1; const pos2 = boxPositions.box2; // 交换transform box1.style.transform = `translate(${pos2.x}px, ${pos2.y}px)`; box2.style.transform = `translate(${pos1.x}px, ${pos1.y}px)`; // 交换存储的位置 boxPositions.box1 = pos2; boxPositions.box2 = pos1; } // 测试:点击容器触发随机移动,双击触发交换 const container = document.querySelector('.container'); container.addEventListener('click', () => moveRandom('box1')); container.addEventListener('dblclick', swapBoxes);
方案2:用requestAnimationFrame 手动控制动画
如果需要更精细的动画控制(比如自定义缓动、中途暂停),可以用requestAnimationFrame手动逐帧更新位置。
JS 示例(基于上面的HTML和CSS,去掉transition)
const box1 = document.getElementById('box1'); let currentX = 0; let currentY = 0; let targetX = 0; let targetY = 0; let animating = false; // 生成随机目标位置 function setRandomTarget() { targetX = currentX + (Math.floor(Math.random() * 200) - 100); targetY = currentY + (Math.floor(Math.random() * 200) - 100); if (!animating) { animate(); } } // 逐帧动画函数 function animate() { animating = true; // 缓动公式(让移动更自然) const speed = 0.05; currentX += (targetX - currentX) * speed; currentY += (targetY - currentY) * speed; box1.style.transform = `translate(${Math.round(currentX)}px, ${Math.round(currentY)}px)`; // 判断是否接近目标,停止动画 if (Math.abs(targetX - currentX) < 0.1 && Math.abs(targetY - currentY) < 0.1) { currentX = targetX; currentY = targetY; animating = false; return; } requestAnimationFrame(animate); } // 点击触发随机移动 document.querySelector('.container').addEventListener('click', setRandomTarget);
关键原理
- 不再依赖CSS动画的初始状态,而是用JS主动跟踪元素的当前偏移量,每次移动都基于这个值计算新位置。
- 用
transform: translate()修改位置,比直接修改left/top性能更好(不会触发重排)。 - 如果需要交换位置,只需交换两个元素的偏移量记录,并更新各自的transform即可。
内容的提问来源于stack exchange,提问作者6y443v3r
相关产品推荐
相关产品推荐

