项目背景
春节想做个不一样的新年祝福页,不要千篇一律的弹窗和表单。于是用纯前端技术实现了一个"点灯祈福"的互动体验:点击灯笼随机出现暖心文案,伴随烟花和铃声,还能放飞自己的愿望。
核心玩法
机制:点击灯笼 → 触发烟花+铃声 → 随机展示祝福文案 → 累计点亮次数和收集进度。
文案池设计:
JavaScript
复制
// 15条预设 + 用户自定义愿望
const blessings = [
"今年,慢一点也没关系。",
"你已经走了很远了。",
"回不回家,都算过年。",
// ...
];
// 用户输入的愿望会混入随机池,下次可能抽到自己的
状态持久化:
JavaScript
复制
localStorage 存储:
- clickCount: 总点击次数
- seenBlessings: 已见过的祝福索引
- customWishes: 用户自定义愿望数组
- musicPlaying: 音乐开关状态
技术亮点
1. Web Audio API 合成铃声(零音频文件)
不用加载 MP3,纯代码生成风铃音效:
JavaScript
复制
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.frequency.setValueAtTime(523.25, t); // C5
oscillator.frequency.exponentialRampToValueAtTime(1046.5, t + 0.1); // 滑音效果
gainNode.gain.setValueAtTime(0.3, t);
gainNode.gain.exponentialRampToValueAtTime(0.01, t + 0.5); // 自然衰减
核心技巧:频率指数 ramp 模拟敲击后的音高衰减,gain 指数 ramp 模拟声音消散。
2. CSS 烟花粒子系统
不用 Canvas,用 DOM + CSS 动画实现:
css
复制
.firework::before {
box-shadow:
0 -20px 0 -2px #ffd700, /* 上 */
14px -14px 0 -2px #ff6b6b, /* 右上 */
20px 0 0 -2px #4ecdc4, /* 右 */
/* ...8个方向 */
}
animation: explode 1s ease-out;
性能优化:用 Element.animate() API 代替 CSS 动画,便于动态创建和清理。
3. 红包雨背景
纯 CSS 动画 + 随机参数:
JavaScript
复制
const packet = document.createElement('div');
packet.style.left = Math.random() * 100 + '%';
packet.style.animationDuration = (5 + Math.random() * 5) + 's';
packet.style.opacity = 0.3 + Math.random() * 0.4;
// 自动清理:setTimeout(() => packet.remove(), 10000)
4. 玻璃拟态 UI
css
复制
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 215, 0, 0.2);
配合深红到暗红的渐变背景,营造"夜晚点灯"的氛围感。
视觉层次设计
表格
复制
| 层级 | 元素 | 技术 |
|---|---|---|
| 背景层 | 渐变底色 + 闪烁星星 | CSS 动画 |
| 氛围层 | 烟花 + 红包雨 | DOM + CSS 动画 |
| 内容层 | 灯笼 + 文案卡片 | 玻璃拟态 + 过渡动画 |
| 交互层 | 按钮 + 输入框 | hover/active 状态 |
灯笼细节:
-
径向渐变模拟球体光照(高光在左上)
-
box-shadow外发光 + 内阴影营造立体感 -
呼吸灯效果(scale 动画)吸引点击
踩坑记录
表格
复制
| 问题 | 解法 |
|---|---|
| 音频自动播放被拦截 | 首次用户点击( lantern )才初始化 AudioContext |
| 烟花粒子内存泄漏 | animation.onfinish 回调中 remove() |
| 文案切换不流畅 | 先 removeClass('show') 触发淡出,再替换文本,延迟后 addClass |
| 移动端点击延迟 | 未用 FastClick,但按钮尺寸足够大(44px+) |
| 自定义愿望混入随机池 | 用 Set 去重索引,但用户愿望用数组长度动态计算偏移 |
数据设计
统计维度:
-
点亮次数:总点击(可重复)
-
收集祝福:去重后的已见文案数(进度感)
分享文案自动生成:
复制
我在"此刻的春节"点亮了${clickCount}盏灯,
收集了${seenBlessings.size}个祝福。
愿这一年,慢一点也没关系。
支持 Web Share API 或降级到剪贴板复制。
最终效果
-
体积:单 HTML 文件,< 12KB
-
依赖:0(纯原生)
-
平台:移动端优先,桌面端兼容
-
特色:无图片、无音频文件、无框架,打开即玩
源码结构
https://ggboypip-ai.github.io/guban/index.html
核心收获:浏览器的多媒体能力(Web Audio + Web Animations)已经足够构建完整的互动体验。春节不需要 Heavy,一盏会响的灯、几句暖心的话、那点红和金,就够了。


