如何用 CSS 动画与 animationend 事件实现循环渐进式圆点动画

本文详解如何通过分离动画类、利用 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是一款自动视频编辑工具,可以将文本、文章或故事转换为视频。

相关推荐
耿雨飞2 小时前
Python 后端开发技术博客专栏 | 第 05 篇 Python 数据模型与标准库精选 -- 写出 Pythonic 的代码
开发语言·python
2301_773553622 小时前
如何自定义修改 Traccar Web 界面模板
jvm·数据库·python
m0_716430072 小时前
CSS如何让响应式图片在容器内居中_利用background-position
jvm·数据库·python
1.14(java)2 小时前
MyBatis 操作数据库
数据库·mybatis
djjdjdjdjjdj2 小时前
如何利用 watchEffect 实现在线人数实时统计?Socket 与响应式结合
jvm·数据库·python
专注VB编程开发20年2 小时前
为何Win内置SQLite却缺驱动?微软只为保住Access中小企业市场,office码头
数据库·microsoft·sqlite
啦啦啦_99992 小时前
0. 工具使用
python
算是难了2 小时前
TypeORM vs Prisma
数据库·typescript·node.js
执笔画流年呀2 小时前
计算机是如何⼯作的
linux·开发语言·python