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

相关推荐
wltx16882 小时前
谷歌SEO如何做插床优化?
大数据·人工智能·python
2301_781571422 小时前
JavaScript中Object-getOwnPropertySymbols获取方法
jvm·数据库·python
倒霉熊dd2 小时前
Python学习(第一部分 语法与数据结构/核心基础)
大数据·python·学习·pip
jump_jump3 小时前
Drizzle 凭什么贴着 Go 跑——从设计哲学到热路径源码
数据库·性能优化·orm
jay神3 小时前
基于SpringBoot的宠物生命周期信息管理系统
java·数据库·spring boot·后端·web开发·宠物·管理系统
仅此,3 小时前
deep agent整合 DeepSeek 记录
python·langchain·agent·deep agent sdk
苍煜3 小时前
生产环境 JVM 参数实战计算指南
jvm
秋93 小时前
MySQL 8.0.46 与 MySQL 9.7.0在sql语句方面的区别并举例说明
数据库·sql·mysql
一只数据集3 小时前
NVIDIA Nemotron AIQ Agentic Safety Dataset:面向企业级智能体系统的安全与防护评估数据集全面解析
网络·数据库·安全
ftpeak3 小时前
AI开发之LangGraph教程6~自定义状态 (Custom State)
python·ai·langchain·langgraph