首页 前端开发 web应用

结婚纪念日页面

tts小陈 发布于 2026-08-04 10:00 更新于 2026-08-04 阅读 7 约 2,735 字 · 阅读 7 分钟
web应用 · 网站

用 PHP + 原生 JS 给老婆做了一个会放烟花的结婚纪念日页面

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


一、原始代码:能跑,但一身毛病

最初是一份 PHP 和 HTML 混写的单文件。功能在,但埋了不少雷:

PHP 部分

  • 自己写了个 Age 类算婚龄:把年月日拼成整数比较、while 循环一位位加、还自建了"每个月多少天"和闰年判断(只判 %4,没管整百年)。又臭又长还容易错。
  • $test = array('2017-03-13') 套个 foreach 循环,数组只有一项,纯属死代码。
  • 婚龄称谓用二十几个 caseswitch 堆出来。

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 样式。

四、一步步加料(迭代乐趣)

地基稳了,开始往上面堆浪漫:

  1. 趣味天数统计:相伴天数 / 周数 / 小时 / "为你心跳次数"(按每分钟 75 次估算)。
  2. 日 / 夜星空主题:右上角一键切换,夜间浮现发光月亮、樱花变星光;用 localStorage 记住选择,首次访问按时间自动判断(晚 7 点到早 6 点默认夜间)。
  3. 一键生成纪念卡片:用 html2canvas 把内容卡片截成 2 倍清晰度 PNG 下载,可直接发朋友圈。
  4. 烟花礼花:Canvas 粒子引擎(带重力、拖尾、随机色),按钮触发;每年 3-13 纪念日与 2-14 情人节当天自动放
  5. 季节 / 节日特效:背景粒子按月份自动切换——春樱花、夏萤火虫、秋枫叶、冬雪花。
  6. 鼠标爱心光晕:光标带柔光晕跟随(夜间变淡紫),移动时偶洒小爱心。
  7. 实时时钟 + 纪念日进度条:显示当前日期/星期/时间,并用一条进度条展示"本婚龄年已过 X%"。
  8. 长按彩蛋:在页面长按约 0.7 秒,屏幕中央浮现一句随机告白并放一波烟花。
  9. 博客首页按钮:右上角 🏠 一键新窗口打开博客。

工具栏最终顺序:🏠 博客 · 🌙 主题 · 📸 卡片 · 🎆 烟花


五、能复用的几个经验

  • 服务器-客户端时钟对齐offset = serverNow - Date.now(),任何需要"倒计时/定时"的前端都该这么做,否则客户端改时间就崩。
  • CSS 渐变文字三件套background(渐变) + -webkit-background-clip: text + -webkit-text-fill-color: transparent,缺一不可,否则文字透明看不见。
  • CSS 里别写 JStransform: translate(Math.random()…) 这类写法永远不会生效,随机量交给 JS 在 style 里设。
  • 性能细节:粒子节点列表缓存一次、别每帧 querySelectorAll;粒子设上限(90~120);临时 DOM 用完 setTimeout 清理,避免无限膨胀。
  • 纯前端也能有氛围:烟花、季节、光晕全是原生 Canvas / CSS / JS,无需任何后端或框架。

六、效果与源码

整页单文件、零后端依赖,带上 love.giffavicon.ico 等同目录资源即可运行。纪念日当天打开,会自动下一场樱花雨 + 烟花。

愿每一段缘分,都值得一个会放烟花的页面。💞

—— 本文记录的页面源码已整理为单文件,欢迎自取改造(只需改一处 $anniversaryDate 即可换成你自己的日子)。

💬 留言 共 0 条 · 登录后可留言
还没有留言,来抢沙发~