H5 Canvas粒子爆炸动画源码拆解:从粒子系统到可配置特效模块
简介这是一份面向前端开发者与网页动效爱好者的H5 Canvas粒子爆炸动画特效源码包适合用于个人主页、活动页或产品展示页的背景动画开发帮助解决静态页面缺乏视觉冲击力的问题。压缩包共6个文件以3个JavaScript脚本为核心配合1个HTML与1个HTM页面、1个CSS样式表整体约59KB体积轻量便于直接嵌入现有项目。代码围绕Canvas 2D渲染上下文展开通过requestAnimationFrame驱动动画循环构建粒子系统模拟彩色粒子的爆炸、位移、变色与消散过程并可将文字轮廓拆解为粒子形成字符随爆炸动态聚合与散开的视觉效果。读者可从中学习粒子对象的属性定义、生命周期管理、重力与速度衰减等物理规则以及批量数组操作与闭包状态保持的写法。目前已有321人学习适合具备一定JavaScript基础、希望掌握高级前端动态效果制作技巧的开发者参考借鉴。1. 从一次页面改版说起这个粒子爆炸动画到底能干什么前阵子帮朋友改一个活动落地页对方丢过来一个压缩包说“就要那种点一下炸开的效果越炫越好但别太重”。打开一看就是这份 H5 Canvas 粒子爆炸动画特效。它干的事很纯粹在 Canvas 画布上生成一批粒子鼠标点击或页面加载时粒子从中心向四周炸开带拖尾、渐隐、重力回落最后自然消散。整个包不依赖任何框架纯原生 JavaScript 加 Canvas 2D 绘制丢进任何 H5 页面、活动页、游戏加载页都能直接用。适合谁一是做营销活动页、需要点击反馈动效的前端二是学 Canvas 动画、想搞懂粒子系统怎么写的初学者三是手里有现成项目想找个轻量特效模块嵌进去的开发者。它不解决业务逻辑只解决“视觉炸裂”这一件事但这件事它做得足够干净代码量小改起来不心疼。下面我按“能干什么 → 怎么跑 → 怎么改”的顺序把这份源码拆开讲。2. 核心架构拆解一个粒子从生成到消散的完整链路2.1 目录结构与文件职责拿到压缩包解压后结构通常很扁平常见做法是下面这样particle-explosion/ ├── index.html # 演示入口含 canvas 容器和基础样式 ├── css/ │ └── style.css # 页面重置、canvas 全屏铺满 ├── js/ │ ├── particle.js # 粒子类位置、速度、颜色、生命周期 │ ├── explosion.js # 爆炸控制器生成粒子、驱动动画循环 │ └── main.js # 入口绑定事件、初始化画布 └── README.mdindex.html只做两件事放一个canvas元素按顺序引入三个 JS。style.css把 body 的 margin 清零canvas 设成display:block避免出现滚动条——这是 Canvas 全屏动画最常见的翻车点很多人第一次跑发现右边和下边有白边就是没处理这个。particle.js是单个粒子的抽象explosion.js是粒子集合的管理器main.js负责把两者和 DOM 事件接起来。这种分层的好处是你想换爆炸形状只动explosion.js的生成逻辑想改粒子外观只动particle.js的绘制方法互不干扰。2.2 粒子类位置、速度与生命周期的三要素粒子系统的核心就三个量位置、速度、寿命。位置决定画在哪速度决定往哪飞寿命决定什么时候消失。看一段典型的粒子类实现// particle.js class Particle { constructor(x, y, options {}) { this.x x; // 当前横坐标 this.y y; // 当前纵坐标 this.vx options.vx || 0; // 横向速度分量 this.vy options.vy || 0; // 纵向速度分量 this.size options.size || 2; // 粒子半径 this.color options.color || #ff6b35; this.life 1; // 生命值1 为满血 this.decay options.decay || 0.015; // 每帧衰减量 this.gravity options.gravity || 0.05; // 重力加速度 } update() { this.vy this.gravity; // 纵向速度受重力影响 this.x this.vx; // 位置随速度更新 this.y this.vy; this.life - this.decay; // 生命值递减 } draw(ctx) { ctx.globalAlpha Math.max(this.life, 0); // 透明度跟随生命值 ctx.fillStyle this.color; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); } isDead() { return this.life 0; } }update()每帧调用一次先加重力再更新位置顺序不能反——先更新位置再加重力粒子会显得“飘”下落感不自然。draw()里用globalAlpha控制透明度粒子越接近死亡越透明这是渐隐效果的关键。decay和gravity是最值得调的两个参数decay越大粒子消失越快gravity越大下落越明显。我一般把decay设在 0.01 到 0.02 之间gravity设在 0.03 到 0.08 之间具体看页面节奏。2.3 爆炸控制器批量生成与动画循环单个粒子没意义爆炸是一批粒子同时朝不同方向飞。控制器负责在触发点周围生成 N 个粒子每个粒子的速度方向按角度均匀分布// explosion.js class Explosion { constructor(canvas) { this.canvas canvas; this.ctx canvas.getContext(2d); this.particles []; this.rafId null; } burst(x, y, count 80) { for (let i 0; i count; i) { // 角度均匀分布保证炸开是个圆 const angle (Math.PI * 2 * i) / count; // 速度加随机扰动避免过于规整 const speed 2 Math.random() * 4; this.particles.push(new Particle(x, y, { vx: Math.cos(angle) * speed, vy: Math.sin(angle) * speed, size: 1 Math.random() * 2, color: hsl(${Math.random() * 60 10}, 90%, 60%), decay: 0.012 Math.random() * 0.008 })); } this.start(); } start() { if (this.rafId) return; // 防止重复启动多个循环 const loop () { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); // 倒序遍历方便删除死亡粒子 for (let i this.particles.length - 1; i 0; i--) { const p this.particles[i]; p.update(); p.draw(this.ctx); if (p.isDead()) this.particles.splice(i, 1); } if (this.particles.length 0) { this.rafId requestAnimationFrame(loop); } else { this.rafId null; // 粒子清空后停掉循环省性能 } }; this.rafId requestAnimationFrame(loop); } }burst()里角度用(Math.PI * 2 * i) / count均匀铺开保证爆炸是个完整的圆而不是一坨。速度加Math.random()扰动是为了避免所有粒子飞得一样远看起来像机械的同心圆。颜色用 HSL 的色相随机控制在暖色区间10 到 70出来的效果偏火焰橙红符合“爆炸”的直觉。start()里有两个细节值得说。一是if (this.rafId) return防止连续点击时启动多个requestAnimationFrame循环那样粒子会越跑越快是新手最容易踩的坑。二是粒子清空后把rafId置空并停止循环不然后台会一直空转页面卡顿的元凶往往就在这。2.4 入口绑定画布尺寸与事件接入main.js把画布尺寸和事件接起来// main.js const canvas document.getElementById(stage); const explosion new Explosion(canvas); function resize() { canvas.width window.innerWidth; canvas.height window.innerHeight; } resize(); window.addEventListener(resize, resize); canvas.addEventListener(click, (e) { const rect canvas.getBoundingClientRect(); explosion.burst(e.clientX - rect.left, e.clientY - rect.top, 100); }); // 页面加载后自动炸一次作为入场动效 window.addEventListener(load, () { explosion.burst(canvas.width / 2, canvas.height / 2, 120); });resize()里直接改canvas.width/height注意这会清空画布内容并重置坐标系所以要在初始化时调用一次。点击坐标用getBoundingClientRect()换算不能直接用e.clientX因为 canvas 不一定贴在页面左上角这是坐标偏移问题的根源。load事件里自动炸一次适合做首屏入场如果不需要删掉即可。3. 跑起来本地启动、参数调试与效果验证3.1 三种运行方式与选择这份源码是纯静态的不需要构建工具。最省事的方式是直接双击index.html浏览器就能跑。但如果你后续要改代码、加模块建议起个本地服务避免file://协议下某些浏览器对资源的限制。用 Python 起服务# 在项目根目录执行Python 3 自带 python -m http.server 8080 # 浏览器访问 http://localhost:8080用 Node 的话装个serve也行npx serve . # 默认 3000 端口按提示访问如果你打算把它嵌进现有项目直接把js/下三个文件和 canvas 标签搬过去注意引入顺序particle.js→explosion.js→main.js因为后者依赖前者的类定义。3.2 关键参数速查与调参方向调参是这份特效最常做的事把几个核心参数列出来改的时候心里有数参数位置默认范围调大效果调小效果countburst 调用处80~120粒子更多更密稀疏、性能更好speedexplosion.js2~6炸得更远聚在中心decayparticle.js0.012~0.02消失更快拖尾更久gravityparticle.js0.03~0.08下落明显悬浮感强sizeparticle.js1~3粒子更粗更细腻调参有个血泪经验别一次改好几个改一个刷新看一次。粒子效果是多个参数叠加出来的同时改容易找不到是哪个起的作用。我一般先定count和speed定整体形态再调decay和gravity定节奏最后微调size和颜色。3.3 验证效果是否正常跑起来后正常表现是页面加载后中心炸开一团暖色粒子向四周飞散并逐渐透明消失点击任意位置在点击处再炸一次。如果出现下面几种情况说明哪里不对粒子全部往一个方向飞检查angle计算是不是漏了Math.PI * 2粒子不消失越积越多检查isDead()和splice逻辑多半是decay没生效点击位置偏移检查有没有用getBoundingClientRect()换算连续点击越来越快检查start()里的rafId防重入判断。4. 避坑与常见问题排查4.1 粒子越点越多、页面越来越卡现象连续快速点击后粒子数量暴涨帧率明显下降。原因每次burst()都往this.particles里 push但没有上限控制点击频率高时粒子数会失控。解决在burst()开头加个上限判断比如if (this.particles.length 500) return;或者用对象池复用死亡粒子避免频繁创建销毁。4.2 画布模糊、粒子边缘发虚现象在高分屏上粒子看起来糊边缘不锐利。原因canvas 的 CSS 尺寸和实际像素尺寸不一致浏览器做了拉伸。解决按devicePixelRatio放大画布实际尺寸再用ctx.scale()缩放坐标系const dpr window.devicePixelRatio || 1; canvas.width window.innerWidth * dpr; canvas.height window.innerHeight * dpr; canvas.style.width window.innerWidth px; canvas.style.height window.innerHeight px; ctx.scale(dpr, dpr);4.3 页面切到后台再回来粒子瞬移或堆积现象切走标签页一段时间再切回粒子位置突变或一次性涌出。原因requestAnimationFrame在后台会暂停但update()里的速度是按帧累加的恢复后时间差没补偿。解决用时间戳计算 delta把速度乘以时间因子而不是每帧固定加。简单点也可以在visibilitychange事件里暂停和恢复动画。4.4 移动端点击没反应或延迟现象手机上点半天不炸或者炸的位置不对。原因移动端有 300ms 点击延迟且触摸事件和鼠标事件模型不同。解决改用touchstart或pointerdown事件pointerdown能同时覆盖鼠标和触摸是现在更推荐的做法。坐标换算逻辑不变e.clientX在 pointer 事件里同样可用。4.5 嵌入现有页面后样式冲突现象搬进项目后 canvas 尺寸不对或者被其他元素盖住。原因canvas 默认是 inline 元素受父容器 line-height 和字体影响且 z-index 没设。解决给 canvas 加display:block; position:fixed; top:0; left:0; z-index:9999; pointer-events:none;pointer-events:none让 canvas 不拦截点击这样它作为背景特效时不会挡住下面的按钮。5. 二次开发从固定爆炸到可配置特效模块把这份源码改造成能复用的模块是我拿到手后做的第一件事。原始代码把参数写死在类里换个页面就得改源码不优雅。我的做法是抽一个配置对象出来让调用方传参// 改造后的调用方式 const fx new Explosion(canvas, { count: 100, speedRange: [2, 6], decayRange: [0.012, 0.02], gravity: 0.05, hueRange: [10, 70], // 暖色 autoBurst: true // 是否加载后自动炸 }); // 想换冷色调只改配置 fx.setOptions({ hueRange: [180, 240] });配置化的关键是给每个参数一个合理的默认值调用方不传也能跑。hueRange控制色相区间暖色是 10 到 70冷色是 180 到 240改一个数组就能换风格比翻源码找颜色值高效得多。再进一步可以把爆炸形状从圆形改成其他图案。核心在burst()里生成速度向量的方式。圆形是角度均匀分布想改成心形就把角度和速度按心形参数方程映射// 心形爆炸的速度方向映射示意 const t (Math.PI * 2 * i) / count; const heartX 16 * Math.pow(Math.sin(t), 3); const heartY -(13 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t)); const scale 0.3; this.particles.push(new Particle(x, y, { vx: heartX * scale, vy: heartY * scale, // ...其余参数 }));这样粒子会朝心形轮廓飞散形成心形爆炸。同理换成星形、文字轮廓都可以只要把目标形状的参数方程代进去。这是粒子系统好玩的地方形状逻辑和粒子逻辑解耦改形状不影响粒子的生命周期管理。验证改造是否成功我一般用三步先看默认配置下效果和原版一致再改一个配置项确认生效最后在移动端和桌面端各跑一遍确认没有平台差异。这套流程走下来基本能保证模块在别的项目里不会翻车。从那以后我每次拿到这类特效源码都强制先跑通默认效果、再抽配置、最后做跨端验证三步缺一不可。希望这份拆解帮到你拿到包能直接跑起来也能按自己的需求改出想要的样子。本文还有配套的精品资源点击获取

相关新闻

STM32开发环境搭建:Eclipse + arm-none-eabi-gcc + J-Link 实战指南

STM32开发环境搭建:Eclipse + arm-none-eabi-gcc + J-Link 实战指南

入行前几年,我一直用一套商业集成环境做 STM32 开发。那时候觉得编译、下载、调试都“一键完成”,挺好的。直到同事把一摊子藏在维护期里的老代码交给我,那套 IDE 的毛病全冒出来了:打开十几万行的工程要卡半分钟,跨平…

2026/10/15 21:14:21 阅读更多 →
SDK-6.0.22.1401嵌入式协议栈实战:Modbus RTU开发与自适应波特率

SDK-6.0.22.1401嵌入式协议栈实战:Modbus RTU开发与自适应波特率

简介:本资源为Dialog Semiconductor DA14585系列蓝牙低功耗SoC专用SDK开发包(v6.0.22.1401),面向嵌入式IoT开发者、可穿戴设备固件工程师及BLE协议栈初学者,用于快速构建低功耗蓝牙应用、外设驱动与协议栈移植。压缩包…

2026/10/15 21:14:21 阅读更多 →
CameraX实战:移动端相机预览与拍照开发指南

CameraX实战:移动端相机预览与拍照开发指南

1. 为什么移动端相机开发总让人头疼做过移动端相机功能的人大概都有类似的体验:打开系统相机拍一张照片,看起来只是调个API的事,但真到自己动手实现预览加拍照的完整链路,坑就一个接一个冒出来了。预览画面拉伸变形、旋转角度对不…

2026/10/15 21:13:20 阅读更多 →

最新新闻

MySQL时间类型选型:DATETIME与TIMESTAMP底层差异与避坑指南

MySQL时间类型选型:DATETIME与TIMESTAMP底层差异与避坑指南

MySQL 的时间类型,尤其是在 DATETIME 和 TIMESTAMP 之间反复纠结的情况,我见过太多了。很多人直到线上出现“时间差8小时”或者“2038年数据写不进去”才发现自己对这两个类型的理解还是靠猜。今天把这俩家伙的底层逻辑、行为差异、性能取舍和选型思路一…

2026/10/15 22:08:39 阅读更多 →
Hive小文件合并实战:Map输入端与输出端参数配置及避坑指南

Hive小文件合并实战:Map输入端与输出端参数配置及避坑指南

1. 为什么HIVE小文件问题总在凌晨三点爆发 做过离线数仓的人大概率都经历过这种场景:凌晨跑批任务,前面几十个ETL节点都绿了,最后一个分区写入的节点卡在99%不动,打开监控一看,Reduce阶段还剩两百多个task在慢慢磨&…

2026/10/15 22:08:39 阅读更多 →
Vibe Coding的隐患:AI生成的代码为何没人敢碰?

Vibe Coding的隐患:AI生成的代码为何没人敢碰?

Vibe Coding为什么“写完就没人敢碰”?最近“Vibe Coding”这个词在开发者圈子里越来越热,代价也越来越明显。简单说,Vibe Coding就是开发者把写代码这件事很大程度上交给AI代码工具,自己只描述意图、提需求,然后接受A…

2026/10/15 22:08:39 阅读更多 →
claude-code下载安装与使用:从winget到cmd的TaoToken接入实践

claude-code下载安装与使用:从winget到cmd的TaoToken接入实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 22:08:39 阅读更多 →
AI Agent Harness 与 CMS 系统集成管控:把 endpoint 改到 TaoToken 的落地大纲

AI Agent Harness 与 CMS 系统集成管控:把 endpoint 改到 TaoToken 的落地大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 22:08:39 阅读更多 →
MySQL表管理完全指南:建表、改表、查表与删表

MySQL表管理完全指南:建表、改表、查表与删表

1. 表管理其实就五件事:今天这堂课先定个范围 上午后两节课排的是MySQL数据库表管理。一听到“表管理”,很多同学第一反应是“不就是CREATE TABLE、DROP TABLE吗,这有什么好讲的”。但真坐到电脑前面开始建表、改表、查表结构、清数据、迁移字…

2026/10/15 22:07:37 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →