本文详解如何通过分离动画类、利用 animationend 事件触发链式执行,配合 setTimeout 实现 10 个圆点依次随机出现、缩放淡出,并无限循环------彻底解决定时器重置导致动画失效的问题。 本文详解如何通过分离动画类、利用 `animationend` 事件触发链式执行,配合 `settimeout` 实现 10 个圆点依次随机出现、缩放淡出,并无限循环------彻底解决定时器重置导致动画失效的问题。要实现「10 个圆点在 1 秒内以 0.1 秒间隔依次随机出现 → 各自从中心缩放放大并透明度归零 → 整个序列无缝循环」的效果,关键不在于堆叠 setTimeout 或强行重启函数,而在于解耦样式状态与动画触发时机。原始代码中直接在 forEach 中连续调用 circ() 并依赖 setTimeout(..., N * 100) 启动动画,会导致所有圆点共享同一轮动画状态;更严重的是,CSS 动画在 class 未变化时不会重播(即使 animation 属性值未变),因此后续循环中 .circle 元素无法再次触发动画。? 正确解法的核心是三步策略: 分离动画控制类:将 animation 声明移至独立类(如 .anim),而非写死在基础 .circle 上; 动态增删动画类:每次展示前先移除 .anim,再通过 setTimeout 异步添加,强制浏览器重绘并触发新动画; 用 animationend 驱动下一轮:每个圆点动画结束时监听事件,递归调度自身下一次出现(形成闭环),避免全局 setTimeout(go, 1000) 破坏节奏。以下是完整可运行实现:<!DOCTYPE html><html><head> <style> body { background-color: #000; width: 100vw; height: 100vh; margin: 0; overflow: hidden; position: relative; /* 确保绝对定位子元素相对于 viewport */ } .circle { position: absolute; border-radius: 50%; transform: translate(-50%, -50%) scale(0.1); /* 初始状态无动画 */ } .anim { animation: scale 1s ease-out forwards; } @keyframes scale { to { transform: translate(-50%, -50%) scale(3); opacity: 0; } } </style></head><body> <!-- 10 个占位圆点 --> <span class="circle"></span> <span class="circle"></span> <span class="circle"></span> <span class="circle"></span> <span class="circle"></span> <span class="circle"></span> <span class="circle"></span> <span class="circle"></span> <span class="circle"></span> <span class="circle"></span> <script> function go() { const circles = document.querySelectorAll('.circle'); const width = window.innerWidth; const height = window.innerHeight; const createCircleStyle = () => { const X = Math.floor(Math.random() * width); const Y = Math.floor(Math.random() * height); const Size = Math.floor((Math.random() * 6) + 5) * 10; const R = Math.floor(Math.random() * 255).toString(16).padStart(2, '0'); const G = Math.floor(Math.random() * 255).toString(16).padStart(2, '0'); const B = Math.floor(Math.random() * 255).toString(16).padStart(2, '0'); return { left: `{X}px\`, top: \`{Y}px`, width: `{Size}px\`, height: \`{Size}px`, backgroundColor: `#{R}{G}${B}` }; }; const animateCircle = (circle) => { const style = createCircleStyle(); // 清除动画类,重置状态 circle.classList.remove('anim'); Object.assign(circle.style, style); // 异步添加动画类,确保样式已应用后再触发动画 setTimeout(() => circle.classList.add('anim'), 0); }; // 为每个圆点绑定 animationend 事件,实现自我循环 circles.forEach((circle, index) => { circle.addEventListener('animationend', () => animateCircle(circle)); // 初始序列:第 i 个圆点延迟 i × 100ms 启动 setTimeout(() => animateCircle(circle), index * 100); }); } // 首次启动 go(); // 可选:响应窗口大小变化(如旋转设备) window.addEventListener('resize', () => { // 重置所有圆点位置/尺寸需重新触发,此处仅做示意 document.querySelectorAll('.circle').forEach(c => c.classList.remove('anim')); }); </script></body></html>? 关键注意事项: Tellers AI Tellers是一款自动视频编辑工具,可以将文本、文章或故事转换为视频。
相关推荐
wltx16882 小时前
谷歌SEO如何做插床优化?2301_781571422 小时前
JavaScript中Object-getOwnPropertySymbols获取方法倒霉熊dd2 小时前
Python学习(第一部分 语法与数据结构/核心基础)jump_jump3 小时前
Drizzle 凭什么贴着 Go 跑——从设计哲学到热路径源码jay神3 小时前
基于SpringBoot的宠物生命周期信息管理系统仅此,3 小时前
deep agent整合 DeepSeek 记录苍煜3 小时前
生产环境 JVM 参数实战计算指南秋93 小时前
MySQL 8.0.46 与 MySQL 9.7.0在sql语句方面的区别并举例说明一只数据集3 小时前
NVIDIA Nemotron AIQ Agentic Safety Dataset:面向企业级智能体系统的安全与防护评估数据集全面解析ftpeak3 小时前
AI开发之LangGraph教程6~自定义状态 (Custom State)