结婚纪念日页面
用 PHP + 原生 JS 给老婆做了一个会放烟花的结婚纪念日页面
域名注册日 2017-03-13,被我定成了咱们的"纪念日"。原本只是个能跑的页面,翻出来重温时越看越不对劲——于是顺手重构了一遍,又一步步加了点料。下面把整个过程记下来,既有踩坑,也有能复用的经验。

一、原始代码:能跑,但一身毛病
最初是一份 PHP 和 HTML 混写的单文件。功能在,但埋了不少雷:
PHP 部分
- 自己写了个
Age类算婚龄:把年月日拼成整数比较、while循环一位位加、还自建了"每个月多少天"和闰年判断(只判%4,没管整百年)。又臭又长还容易错。 $test = array('2017-03-13')套个foreach循环,数组只有一项,纯属死代码。- 婚龄称谓用二十几个
case的switch堆出来。
CSS / 前端部分(不少是 bug)
- 标题写了
color: transparent+background-clip: text,却没给渐变背景,文字实际上不可见,全靠 JS 随机色兜底。 - 樱花
fall关键帧里写了Math.random()——CSS 不支持 JS 函数,动画直接失效;加上.sakura初始opacity: 0且 JS 从不改透明度,樱花基本看不见。 - 点击生成的
.bloom-flower完全没有样式(display: 'visible'也不是合法值),点了什么也看不到。 - 有一堆
canvas的样式却是死代码——页面里根本没有<canvas>。 body的样式被重复定义(基础80vh和媒体查询里的55vh冲突),布局不一致。
二、先把地基打稳:PHP 重构
1. 用原生 DateTime 干掉手写日期算法
function calcDuration(DateTime $start, DateTime $now): array {
$invert = $now < $start;
$diff = $now->diff($start);
return [
'year' => $diff->y, 'month' => $diff->m, 'day' => $diff->d,
'not_birth' => $invert ? 1 : 0,
];
}
一行 DateTime::diff() 替代了原来约 70 行的脆弱逻辑,闰年问题彻底消失。
2. 婚龄称谓 switch → 关联数组查表
$marriageNames = [
6 => '糖婚:幸福美满,如花儿一般',
7 => '铜婚:相濡以沫',
// …… 新增/修改只动一行
];
$output = $marriageNames[$years] ?? "结婚:{$years} 年 {$months} 个月零 {$days} 天";
3. 倒计时消除漂移
原来用 setInterval(1000) 逐秒递减、嵌套 if 借位,时间长了必然错位。改成把"下一个纪念日的时间戳"传给前端,并用服务器时间对齐客户端时钟,每帧真实计算剩余时间:
$nextAnniv = new DateTime($now->format('Y') . '-03-13');
if ($now > $nextAnniv) $nextAnniv->modify('+1 year');
$targetTs = $nextAnniv->getTimestamp();
const serverNow = <?= $now->getTimestamp() ?> * 1000;
const offset = serverNow - Date.now(); // 校正客户端/服务器时间差
const target = <?= $targetTs ?> * 1000 + offset;
三、让页面"看得见":CSS / 动效修复与美化
- 渐变文字标题:补上真正的线性渐变背景 +
background-clip: text+sweep动画,并引入中文书法体Ma Shan Zheng。 - 纯 CSS 樱花花瓣:用
border-radius: 100% 0 100% 0+ 渐变画出花瓣,不依赖任何图片资源,再修掉opacity和无效关键帧的问题。 - 点击开花 + 上升爱心:给
.bloom-flower加了bloom缩放动画,点击时绽放小花并喷出一串向上飘散的爱心。 - 毛玻璃内容卡片:半透明背景 +
backdrop-filter+ 柔和阴影,整页配色统一成浪漫粉。 - 删掉无用的
canvas死代码,合并冲突的body样式。
四、一步步加料(迭代乐趣)
地基稳了,开始往上面堆浪漫:
- 趣味天数统计:相伴天数 / 周数 / 小时 / "为你心跳次数"(按每分钟 75 次估算)。
- 日 / 夜星空主题:右上角一键切换,夜间浮现发光月亮、樱花变星光;用
localStorage记住选择,首次访问按时间自动判断(晚 7 点到早 6 点默认夜间)。 - 一键生成纪念卡片:用 html2canvas 把内容卡片截成 2 倍清晰度 PNG 下载,可直接发朋友圈。
- 烟花礼花:Canvas 粒子引擎(带重力、拖尾、随机色),按钮触发;每年 3-13 纪念日与 2-14 情人节当天自动放。
- 季节 / 节日特效:背景粒子按月份自动切换——春樱花、夏萤火虫、秋枫叶、冬雪花。
- 鼠标爱心光晕:光标带柔光晕跟随(夜间变淡紫),移动时偶洒小爱心。
- 实时时钟 + 纪念日进度条:显示当前日期/星期/时间,并用一条进度条展示"本婚龄年已过 X%"。
- 长按彩蛋:在页面长按约 0.7 秒,屏幕中央浮现一句随机告白并放一波烟花。
- 博客首页按钮:右上角 🏠 一键新窗口打开博客。
工具栏最终顺序:🏠 博客 · 🌙 主题 · 📸 卡片 · 🎆 烟花。
五、能复用的几个经验
- 服务器-客户端时钟对齐:
offset = serverNow - Date.now(),任何需要"倒计时/定时"的前端都该这么做,否则客户端改时间就崩。 - CSS 渐变文字三件套:
background(渐变) +-webkit-background-clip: text+-webkit-text-fill-color: transparent,缺一不可,否则文字透明看不见。 - CSS 里别写 JS:
transform: translate(Math.random()…)这类写法永远不会生效,随机量交给 JS 在style里设。 - 性能细节:粒子节点列表缓存一次、别每帧
querySelectorAll;粒子设上限(90~120);临时 DOM 用完setTimeout清理,避免无限膨胀。 - 纯前端也能有氛围:烟花、季节、光晕全是原生 Canvas / CSS / JS,无需任何后端或框架。
六、效果与源码
整页单文件、零后端依赖,带上 love.gif、favicon.ico 等同目录资源即可运行。纪念日当天打开,会自动下一场樱花雨 + 烟花。
愿每一段缘分,都值得一个会放烟花的页面。💞
—— 本文记录的页面源码已整理为单文件,欢迎自取改造(只需改一处 $anniversaryDate 即可换成你自己的日子)。
💬 留言 共 0 条 · 登录后可留言
还没有留言,来抢沙发~
🔑 登录后可留言