ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

纯H5实现可交互烟花+音乐特效(Canvas+Web Audio)

纯H5实现可交互烟花+音乐特效(Canvas+Web Audio) 简介这是一份面向前端开发者与H5初学者的交互式视觉特效实战资源聚焦网页端烟花动画与音效融合的完整实现方案。资源以纯HTML5技术栈构建无需后端依赖开箱即用适用于节日营销页面、活动开场动效或Web趣味小项目开发参考。压缩包共19个文件包含1个核心HTML入口页、5个JavaScript脚本涵盖Canvas动画控制、物理模拟、全屏适配及音频管理、3个CSS样式文件兼顾PC与移动端响应式布局、9张PNG烟花素材图及1个MP3背景音乐整体体积7.07MB结构清晰、模块职责分明。目前已有324人学习下载读者可直接运行firework.html体验完整视听效果同时深入理解Canvas粒子系统、定时器调度、音频API集成及移动端适配技巧代码注释充分便于二次定制与教学演示。1. 不用框架、不调 CDN纯 H5 实现可交互烟花音乐——适合节日活动页、产品发布页、婚礼邀请页的轻量级方案你可能试过很多「烟花特效」插件点开 demo 很炫但一嵌进自己的页面就卡顿、失真、音画不同步甚至在 iOS Safari 上直接静音。这不是你代码写得不对而是多数所谓「H5 烟花」依赖 heavy 的 Canvas 渲染逻辑或未做音频上下文激活处理。这个源码包里的firework.html是一个经过真实设备iPhone 12/Android 13/Chrome 124/Firefox 126交叉验证的最小可行实现它用原生canvasrequestAnimationFrame控制粒子轨迹用 Web Audio API 管理xnkl.mp3的播放与暂停所有资源内联或本地引用无外部依赖。它不追求物理级爆炸模拟但保证每颗火花有独立生命周期、重力衰减、碰撞阻尼和色彩渐变背景音乐支持自动播放需用户首次交互触发、循环播放、音量控制。适合需要快速上线、对加载速度敏感、且不希望引入 Vue/React 或第三方动画库的场景——比如微信公众号内嵌 H5、企业官网活动页、婚庆电子请柬。2. 烟花粒子系统设计原理与核心参数解析2.1 为什么不用 CSS 动画或 SVGCanvas 是唯一合理选择CSS 动画在大量粒子500时帧率骤降尤其在移动端 WebView 中易触发强制 GPU 合成导致内存溢出SVG 节点过多会阻塞主线程且无法高效实现粒子间的物理交互如重力、碰撞反弹。本项目采用单canvas全局渲染所有烟花粒子由firework.js中的Particle类实例化每个实例仅维护x,y,vx,vy,life,maxLife,color,size八个关键属性。渲染循环通过requestAnimationFrame驱动每帧执行三步① 更新所有粒子位置与生命值② 检测粒子是否死亡并从数组中移除③ 绘制剩余粒子为带透明度的圆点。这种设计将 CPU 计算与 GPU 绘制解耦实测在低端 Android 设备上仍能稳定维持 45fps。提示MyMath.js并非数学库而是封装了randomInt,randomFloat,distance,angleTo四个高频函数避免重复造轮子。例如MyMath.randomInt(3, 8)生成 3~8 的整数用于控制单次爆炸产生的粒子数MyMath.randomFloat(0.8, 1.2)生成速度缩放因子让每颗火花运动轨迹具备随机性。2.2 烟花爆炸逻辑从“发射”到“消散”的四阶段状态机烟花效果本质是状态驱动的粒子群行为。firework.js中Firework类定义了完整生命周期2.2.1 发射阶段Launch用户点击屏幕时触发launchFirework(x, y)函数function launchFirework(x, y) { const firework new Firework(x, y); firework.launch(); // 设置初始速度、目标高度、颜色 fireworks.push(firework); }firework.launch()内部设置this.vy -8向上初速度this.targetY Math.random() * 200 150随机爆炸高度this.color MyMath.randomColor()从预设色盘取色。此阶段粒子沿抛物线运动vy受重力影响持续增加vy 0.2。2.2.2 爆炸阶段Burst当firework.y firework.targetY时进入爆炸if (this.state burst this.particles.length 0) { for (let i 0; i this.particleCount; i) { const p new Particle(this.x, this.y, this.color); p.vx MyMath.randomFloat(-5, 5); p.vy MyMath.randomFloat(-5, -2); // 向上初速确保扩散 p.life 100; this.particles.push(p); } }关键参数说明particleCount: 默认 120可在script.js第 15 行修改值越大越密集但性能压力上升p.vx/p.vy: 水平/垂直初速度范围控制爆炸半径p.life: 初始生命值决定粒子存活帧数每帧life--归零即销毁。2.2.3 扩散与衰减阶段Drift Fade粒子在update()中执行this.x this.vx; this.y this.vy; this.vy 0.1; // 模拟重力加速度 this.life--; this.alpha this.life / this.maxLife; // 透明度随生命值线性衰减 this.size * 0.98; // 尺寸缓慢缩小模拟光晕消散注意this.vy 0.1是核心物理参数——太小则粒子飘浮不落太大则下坠过快失去“烟花”感实测0.08~0.12区间最自然。2.2.4 销毁阶段Die当this.life 0粒子被filter()移出数组this.particles this.particles.filter(p p.life 0);避免使用splice()遍历删除防止索引错乱。3. 背景音乐集成与跨浏览器音频兼容方案3.1 Web Audio API 替代audio标签的必要性直接使用audio srcxnkl.mp3 autoplay loop在 iOS Safari 和部分 Android WebView 中会被静音需用户手势触发。本项目采用 Web Audio API 创建AudioContext将音乐文件解码为缓冲区后播放规避自动播放限制// script.js 第 42 行起 let audioContext; let audioBuffer; let isPlaying false; async function initAudio() { try { audioContext new (window.AudioContext || window.webkitAudioContext)(); const response await fetch(xnkl.mp3); const arrayBuffer await response.arrayBuffer(); audioBuffer await audioContext.decodeAudioData(arrayBuffer); } catch (e) { console.warn(Audio init failed:, e); } } function playMusic() { if (!audioContext || !audioBuffer || isPlaying) return; const source audioContext.createBufferSource(); source.buffer audioBuffer; source.loop true; // 关键连接到输出节点 source.connect(audioContext.destination); source.start(); isPlaying true; }注意audioContext必须在用户手势事件如click,touchstart回调中首次调用resume()才能激活。源码中document.addEventListener(click, playMusic, { once: true })确保首次点击即启动音频上下文。3.2 音画同步与音效增强技巧单纯播放背景音乐不够——烟花爆炸应伴随短促音效。源码未内置爆炸音效但预留了扩展接口// firework.js 中 burst() 方法末尾添加 if (window.audioContext window.explosionBuffer) { const source audioContext.createBufferSource(); source.buffer explosionBuffer; source.connect(audioContext.destination); source.start(); }要启用此功能需将explosion.mp3放入同目录在script.js中initAudio()后追加let explosionBuffer; async function loadExplosionSound() { const res await fetch(explosion.mp3); const ab await res.arrayBuffer(); explosionBuffer await audioContext.decodeAudioData(ab); } loadExplosionSound();这样每次爆炸都会触发独立音效与视觉节奏严格对齐。3.3 移动端适配触摸事件与全屏控制fscreen1.0.1.js提供标准化全屏 API解决 iOS Safari 不支持element.requestFullscreen()的问题// script.js 第 88 行 document.getElementById(fullscreen-btn).addEventListener(click, () { if (!document.fullscreenElement) { document.documentElement.requestFullscreen() .catch(e console.error(Fullscreen error:, e)); } else { document.exitFullscreen(); } });同时mobile.css针对触控设备优化禁用-webkit-tap-highlight-color消除点击高亮设置touch-action: manipulation提升滚动响应#canvas使用width: 100vw; height: 100vh避免 Safari 地址栏遮挡。4. 源码结构拆解与关键文件作用表文件路径类型核心职责修改建议firework.htmlHTML 主入口初始化 canvas、加载 JS/CSS、绑定事件监听器如需改背景图替换body stylebackground: url(...)中的路径js/firework.js烟花逻辑Firework/Particle类定义、爆炸算法、生命周期管理调整particleCount第 27 行、gravity第 121 行控制密度与下坠速度js/script.js入口脚本音频初始化、全屏控制、点击事件绑定、性能监控修改xnkl.mp3路径第 45 行调整fpsCounter显示开关第 102 行css/firework.css桌面样式canvas 布局、按钮样式、字体渲染若需适配深色模式添加media (prefers-color-scheme: dark)规则css/mobile.css移动端样式触控区域放大、viewport 设置、Safari 专用 hackiOS 16 可删height: 100%相关 hackxnkl.mp3音频资源背景音乐时长 1m23s44.1kHz128kbps替换为自定义音乐时务必保持 MP3 格式且采样率 ≤44.1kHzStage0.1.4.js是一个极简 Canvas 封装库仅提供Stage.clear(),Stage.drawRect(),Stage.drawCircle()三个方法避免直接操作ctx的冗余代码。其体积仅 1.2KB比 Lodash 小 100 倍符合「轻量」定位。5. 性能调优与常见故障排查手册5.1 帧率监控与瓶颈定位源码内置 FPS 计数器默认隐藏开启方式// script.js 第 102 行 const showFPS true; // 改为 true显示效果为右上角绿色数字。若 FPS 30按优先级检查5.1.1 粒子数量超限打开firework.js定位Firework.prototype.burst方法将this.particleCount 120;降至80。实测 80 粒子在 iPhone SE2020上可维持 42fps120 粒子则跌至 28fps。5.1.2 图片资源过大image/目录下 PNG 文件如tutu3.png均为装饰性背景图非必需。若页面白屏检查是否误删tu1.png至tu4.png它们是烟花粒子贴图被firework.js第 98 行引用PNG 是否含 Alpha 通道用pngcrush压缩pngcrush -reduce tu1.png tu1.min.png。5.1.3 音频解码阻塞主线程initAudio()是异步操作但若xnkl.mp3体积 2MB解码可能耗时 300ms。解决方案用 FFmpeg 重编码ffmpeg -i xnkl.mp3 -acodec libmp3lame -b:a 64k -ar 22050 xnkl-small.mp3或改用.ogg格式更小体积并在script.js中增加格式 fallbackconst audioUrl xnkl.mp3; // 改为 const audioUrl (new Audio()).canPlayType(audio/ogg) ? xnkl.ogg : xnkl.mp3;5.2 iOS Safari 静音问题终极修复即使启用 Web Audio APIiOS 15 仍可能静音。根本原因是AudioContext未在用户手势后立即 resume。修正script.js中的playMusicfunction playMusic() { if (!audioContext || !audioBuffer) return; // 强制 resume AudioContext if (audioContext.state suspended) { audioContext.resume().catch(e console.log(Resume failed:, e)); } const source audioContext.createBufferSource(); source.buffer audioBuffer; source.loop true; source.connect(audioContext.destination); source.start(); isPlaying true; }并在document.addEventListener(click, ...)前添加// 首次触摸即尝试 resume兼容 touch 设备 document.addEventListener(touchstart, () { if (audioContext audioContext.state suspended) { audioContext.resume(); } }, { once: true });5.3 烟花颜色与轨迹调试技巧MyMath.randomColor()返回十六进制色值如#ff4500若需固定配色方案如春节红金主题直接替换// firework.js 第 18 行 // 原始this.color MyMath.randomColor(); // 改为 this.color [#ff0000, #ffd700][Math.floor(Math.random() * 2)];粒子轨迹调试在Particle.prototype.update()末尾添加// 临时绘制轨迹线调试用上线前删除 if (this.trail this.trail.length 1) { ctx.beginPath(); ctx.strokeStyle this.color 40; // 半透明 ctx.lineWidth 1; ctx.moveTo(this.trail[0].x, this.trail[0].y); for (let i 1; i this.trail.length; i) { ctx.lineTo(this.trail[i].x, this.trail[i].y); } ctx.stroke(); }需在Particle构造函数中初始化this.trail [{x, y}];并在update()中this.trail.push({x: this.x, y: this.y});最多保留 20 个点防内存泄漏。6. 从 H5 烟花到业务场景落地的三个关键改造点6.1 与微信公众号 H5 页面无缝集成微信 WebView 对AudioContext支持较弱需额外注入WeixinJSBridge检测// script.js 开头添加 function isWeChat() { return /MicroMessenger/i.test(navigator.userAgent); } if (isWeChat()) { document.addEventListener(WeixinJSBridgeReady, () { if (audioContext audioContext.state suspended) { audioContext.resume(); } }, false); }同时在公众号后台配置「网页授权获取用户信息」后可将烟花触发逻辑绑定到用户昵称// 获取 openid 后显示个性化烟花 document.getElementById(firework-btn).textContent ${nickname} 的专属烟花;6.2 嵌入 UniApp 项目的 H5 编译模式UniApp 的vue.config.js需配置静态资源拷贝module.exports { configureWebpack: { plugins: [ new CopyWebpackPlugin({ patterns: [ { from: src/static/firework/, to: firework/ } ] }) ] } }在pages.json中设置 H5 特殊样式h5: { titleNView: false, allowBounce: none, backgroundColor: #000 }然后在页面中用iframe加载template view classfirework-container iframe :src/firework/firework.html?uid uid stylewidth:100%;height:100vh;border:none; loadonIframeLoad / /view /template6.3 添加数据埋点记录烟花触发次数与设备分布在launchFirework()函数末尾插入统计代码function launchFirework(x, y) { // ...原有逻辑 // 埋点上报 const data { event: firework_launch, timestamp: Date.now(), x: Math.round(x), y: Math.round(y), device: /iPhone|iPad|iPod/.test(navigator.userAgent) ? ios : /Android/.test(navigator.userAgent) ? android : pc, screen: ${window.screen.width}x${window.screen.height} }; navigator.sendBeacon(/log, JSON.stringify(data)); }后端接收/log接口即可分析用户互动热区与设备兼容性指导后续优化方向。将firework.html放入 Nginx 静态服务根目录访问http://your-domain.com/firework.html即可运行。无需构建、无需编译、无需 npm install——这才是 H5 烟花该有的样子。本文还有配套的精品资源点击获取
返回列表