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
相关产品推荐
相关产品推荐

