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

Shaking Effect仅单次生效:点击元素晃动缩小重置功能故障排查

问题分析与解决方案

咱们先来拆解你代码里导致“第一次晃动后不再晃动”的几个关键问题:

1. 状态变量rotated未正确切换

你定义了rotated用来控制旋转角度,但在点击事件里设置完旋转后,完全没有更新rotated的状态。这就导致每次点击时,deg始终是30deg,根本触发不了反向旋转的逻辑,自然没法来回晃动。

2. res()函数逻辑完全无效

res()函数里的deg不管rotated是什么值都固定为0,完全起不到“来回晃动”的作用;而且你用setInterval(res,140)会持续执行这个函数,但它只会把元素钉死在rotate(0deg),后续的晃动自然就看不到了。

3. 事件绑定方式混乱

HTML里给#box绑定了onclick="clicked()",但clicked()函数内部又重新给box.onclick赋值,这会导致第一次点击后,原有的事件绑定被覆盖,后续点击的逻辑完全偏离你预期的效果。

4. 定时器未清理

每次点击都创建新的setInterval,但从来没有清除旧的定时器,多个定时器同时运行会把元素的状态搅得一团糟。


修复后的完整代码

我帮你重构了代码,完美实现“点击时来回晃动+缩小,尺寸到阈值后重置”的效果:

HTML

<div id="cont">
  <div id="box"></div>
</div>

CSS

body {
  background-color: #ccc;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

#cont {
  width: 90%;
  height: 100vh;
  background-color: white;
  position: absolute;
  left: 5%;
  top: 0;
  pointer-events: all;
}

#box {
  background-color: black;
  width: 15%;
  height: 24.6%;
  transition: all 0.15s ease-in-out; /* 加快过渡速度,晃动更自然 */
  position: absolute;
  top: 35.7%;
  left: 41.7%;
  cursor: pointer;
}

JavaScript

let rotated = false;
let height = 24.6;
let width = 15;
let points = 0;
let shakeTimer = null; // 存储晃动定时器,方便后续清理

// 缩小元素尺寸的逻辑
function shrinkBox() {
  width /= 1.1;
  height /= 1.1;
}

// 实现来回晃动的核心逻辑:切换旋转角度
function shakeBox() {
  const div = document.getElementById('box');
  // 来回切换旋转角度:0 ↔ 30 ↔ 0 ↔ -30 ↔ 0...
  const currentDeg = div.style.transform.match(/rotate\((-?\d+)deg\)/);
  const deg = rotated 
    ? (currentDeg && currentDeg[1] === '30' ? -30 : 0) 
    : 30;
  div.style.transform = `rotate(${deg}deg)`;
  rotated = !rotated;
}

// 重置元素旋转状态并清理定时器
function resetRotation() {
  const div = document.getElementById('box');
  div.style.transform = 'rotate(0deg)';
  rotated = false;
  if (shakeTimer) {
    clearInterval(shakeTimer);
    shakeTimer = null;
  }
}

// 游戏规则:处理尺寸缩小与重置逻辑
function gameRule() {
  const div = document.getElementById('box');
  div.style.width = `${width}%`;
  div.style.height = `${height}%`;

  if (width < 1) {
    // 重置元素尺寸
    width = 15;
    height = 24.6;
    // 暂时禁用点击
    document.getElementById("cont").style.pointerEvents = "none";
    // 1秒后恢复点击
    setTimeout(() => {
      document.getElementById("cont").style.pointerEvents = "all";
    }, 1000);
    points++;
    console.log(`当前分数:${points}`);
  }
}

// 页面加载完成后统一绑定事件
document.addEventListener('DOMContentLoaded', () => {
  const box = document.getElementById('box');
  const cont = document.getElementById('cont');

  // 点击容器时缩小元素,并重置晃动状态
  cont.addEventListener('click', () => {
    shrinkBox();
    resetRotation();
  });

  // 点击盒子时触发晃动
  box.addEventListener('click', (e) => {
    e.stopPropagation(); // 阻止事件冒泡到容器,避免误触发缩小逻辑
    // 如果已有晃动定时器,先清理
    if (shakeTimer) clearInterval(shakeTimer);
    // 启动晃动定时器
    shakeTimer = setInterval(shakeBox, 140);
    // 3秒后自动停止晃动(可根据需求调整时长)
    setTimeout(resetRotation, 3000);
  });

  // 启动游戏规则定时器
  setInterval(gameRule, 10);
});

关键修复点说明

  • 修正状态切换:在shakeBox()里每次切换旋转角度时,同步更新rotated的状态,真正实现来回晃动的效果。
  • 定时器管理:每次启动新的晃动定时器前,先清除旧的,避免多个定时器冲突导致状态混乱。
  • 事件冒泡处理:点击#box时用e.stopPropagation()阻止事件冒泡到父容器,避免误触发缩小逻辑。
  • 简化事件绑定:在DOM加载完成后统一绑定事件,彻底解决重复覆盖事件的问题。
  • 体验优化:调整过渡动画速度让晃动更自然,同时增加了自动停止晃动的逻辑(可按需修改时长)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:10:30