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

JavaScript实现立方体拖拽旋转:解决点击重置角度问题

解决立方体拖拽旋转重置位置的问题

你的问题出在每次拖拽时,旋转角度都是基于鼠标按下瞬间的坐标计算偏移,没有保存上次拖拽结束后的最终旋转状态。要解决这个问题,只需要记录累计的旋转角度,每次拖拽都在已有角度的基础上叠加偏移量即可。

修改后的完整代码

JavaScript 部分

// Select the Cube
const cube = document.querySelector(".cube");
const body = document.querySelector("body");

// 保存累计的旋转角度
let currentX = 0;
let currentY = 0;

// Get the x, y position when click
window.addEventListener("mousedown", function(e) {
  const startX = e.clientX;
  const startY = e.clientY;
  // 记录按下时的当前角度,避免拖拽初始瞬间跳动
  const initialX = currentX;
  const initialY = currentY;

  // rotate
  window.addEventListener("mousemove", moveRotate);

  function moveRotate(e) {
    // 计算鼠标移动的偏移量
    const deltaX = e.clientX - startX;
    const deltaY = e.clientY - startY;
    // 在已有角度基础上叠加偏移量
    cube.style.transform = `
      rotateX(${initialY + deltaY / -2}deg)
      rotateY(${initialX + deltaX / 2}deg)`;

    body.style.cursor = "grabbing";
  }

  window.addEventListener("mouseup", function() {
    // 更新累计角度为当前最终旋转角度
    const transform = cube.style.transform;
    // 从transform字符串中提取当前的rotateX和rotateY值
    const xMatch = transform.match(/rotateX\((-?\d+\.?\d*)deg\)/);
    const yMatch = transform.match(/rotateY\((-?\d+\.?\d*)deg\)/);
    if (xMatch) currentY = parseFloat(xMatch[1]);
    if (yMatch) currentX = parseFloat(yMatch[1]);

    window.removeEventListener("mousemove", moveRotate);
    body.style.cursor = "context-menu";
  });
});

CSS 部分(无需修改)

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background: rgb(0, 0, 0);
}

.cube {
  position: absolute;
  width: 300px;
  height: 300px;
  transform-style: preserve-3d;
}

.cube div {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}

.cube div span {
  color: azure;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(black, rgb(0, 255, 0));
  transform: rotateY(calc(90deg * var(--i))) translateZ(150px);
}

.top {
  position: absolute;
  top: 0;
  left: 0;
  width: 300px;
  height: 300px;
  background: #222;
  transform: rotateX(90deg) translateZ(150px);
}

.top div {
  color: white;
  position: absolute;
  top: 45%;
  left: 35%
}

.bottom {
  position: absolute;
  top: 0;
  left: 0;
  width: 300px;
  height: 300px;
  background: rgba(0, 255, 0);
  transform: rotateX(90deg) translateZ(-150px);
}

HTML 部分(无需修改)

<body>
  <div class="cube">
    <div class="top"></div>
    <div class="bottom"></div>
    <div class="sides">
      <span class=front style="--i:0;">0</span>
      <span class=left style="--i:1;">1</span>
      <span class=back style="--i:2;">2</span>
      <span class=right style="--i:3;">3</span>
    </div>
  </div>
</body>

关键修改说明

  1. 新增累计角度变量:currentX和currentY用来保存每次拖拽结束后的最终旋转角度,初始值为0。
  2. 鼠标按下时记录初始状态:保存按下瞬间的鼠标位置和当前累计角度,避免拖拽开始时立方体突然跳动。
  3. 拖拽时叠加偏移量:旋转角度不再直接用鼠标偏移量,而是用初始累计角度加上偏移量的比例值,实现基于上次状态的连续旋转。
  4. 鼠标松开时更新累计角度:从元素的transform样式中提取当前的旋转角度,更新到currentX和currentY,为下一次拖拽做准备。

内容的提问来源于stack exchange,提问作者vito

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 18:30:43