You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 15:20:55