从灵感到现实:我是如何开发春节灯笼油猴脚本的
前言
最近快到春节了,想着能不能给浏览器也来点节日气氛。在 GitHub 上看到了一个很不错的灯笼项目,给了我很大启发。于是决定自己动手,开发一个功能更全面的春节灯笼油猴脚本。
经过几天的开发、调试和优化,终于完成了这个包含 17项增强功能 的完全版本!今天就来分享一下整个开发过程。
灵感来源
最初的想法很简单:给所有网页挂上灯笼,增加节日气氛。
参考了 zggmd/spring-lantern 项目,发现:
- 灯笼使用 CSS 动画实现摆动效果
- 通过 box-shadow 实现发光效果
- 鼠标靠近时灯笼会隐藏(不影响正常浏览)
但我觉得还可以做得更好——为什么不能让用户自己控制灯笼的显示、颜色、文字呢?
项目定位
核心目标
- 给所有网站添加春节灯笼 - 自动适配任何网页
- 高度可定制化 - 让每个用户都能按自己的喜好调整
- 丝滑流畅的动画 - 使用 CSS3 动画,保证性能
- 简单易用的控制面板 - 所有设置一目了然
技术栈选择
- 纯 JavaScript - 无依赖,轻量级
- CSS3 Animations - GPU 加速,性能优秀
- LocalStorage - 配置持久化,刷新页面不丢失
- 事件委托 - 解决动态渲染的事件绑定问题
开发过程
第一阶段:基础功能实现
1. 灯笼的 CSS 实现
灯笼的形状完全用 CSS 绘制:
.spring_lantern__deng {
position: relative;
width: 120px;
height: 90px;
background: rgba(216, 0, 15, 0.8); /* 红色背景 */
border-radius: 50% 50%; /* 椭圆形 */
animation: swing 3s infinite ease-in-out; /* 摆动动画 */
box-shadow: -5px 5px 50px 4px rgba(250, 108, 0, 1); /* 发光效果 */
}
难点:
- 如何用 CSS 画出不规则的灯笼形状?
- 如何实现自然的摆动效果?
解决方案:
- 使用
border-radius: 50% 50%创建椭圆 - 多层嵌套
div实现灯笼内部结构 transform-origin: 50% -100px让摆动支点在顶部悬挂处
2. 摆动动画的优化
最初的动画比较生硬,后来改进了:
@keyframes swing {
0% { transform: rotate(-10deg) }
50% { transform: rotate(10deg) }
100% { transform: rotate(-10deg) }
}
优化点:
- 使用
cubic-bezier缓动函数,让动画更自然 - 不同灯笼设置不同的动画时长(3s、5s),增加随机感
- 使用
will-change: transform触发 GPU 加速
3. 鼠标交互 - 最大的技术挑战
需求:鼠标靠近灯笼时平滑淡出
第一版方案(有问题):
// 简单的 y 坐标判断
if (e.clientY < 220) {
lantern.style.display = 'none';
}
问题:
- 动画不丝滑,突然消失
- 鼠标离开后动画从头开始,不自然
最终方案:
// 1. 检测鼠标是否在灯笼区域内
function isMouseNearLantern(x, y) {
const distance = 180; // 可调节的触发距离
// 左侧灯笼区域
const leftArea = { x: 0, y: 0, width: 200, height: distance };
// 右侧灯笼区域
const rightArea = { x: window.innerWidth - 200, y: 0, width: 200, height: distance };
return isInArea(x, y, leftArea) || isInArea(x, y, rightArea);
}
// 2. 使用 CSS class 切换,而不是 display
if (isNearLantern) {
lanternItem.classList.add('spring_lantern__fade-out');
} else {
lanternItem.classList.remove('spring_lantern__fade-out');
}
CSS 平滑过渡:
.spring_lantern__fade-out {
opacity: 0 !important;
transform: scale(0.8) translateY(-20px) !important;
transition: opacity 0.4s ease-out,
transform 0.4s ease-out; /* 关键!丝滑过渡 */
}
核心技巧:
- 不使用
display: none(会重置动画) - 使用
opacity+transform实现淡出 - 动画从当前位置继续,不会重置
第二阶段:功能增强
1. 控制面板的设计
用户需要一个界面来调整各种设置。我设计了一个悬浮面板:
技术挑战:
- 如何在不影响原网页的情况下嵌入控制面板?
- 如何让面板既美观又实用?
解决方案:
// 使用高 z-index 确保面板在最上层
panel.style.zIndex = '999999';
// 使用事件委托处理所有开关点击
panel.addEventListener('click', (e) => {
const switchEl = e.target.closest('.switch');
if (!switchEl) return;
const configKey = switchEl.dataset.config;
config[configKey] = !config[configKey];
applyConfig();
});
UI 设计亮点:
- 卡片式布局,分组清晰
- 渐变色背景,节日氛围
- 滑块实时预览
- 开关按钮丝滑动画
2. 自定义文字功能
需求:用户想自己写灯笼上的字
实现:
// 支持输入1-4个汉字
function updateLanternText(text) {
const chars = text.split('');
document.getElementById('left').textContent = chars[0] || '迎';
document.getElementById('right').textContent = chars[1] || '春';
// 如果是3-4个灯笼
if (chars.length >= 3) {
document.getElementById('center1').textContent = chars[2] || '福';
}
if (chars.length >= 4) {
document.getElementById('center2').textContent = chars[3] || '寿';
}
}
额外功能:
- 12个预设文字模板(迎春、福、喜、财源、吉祥等)
- 点击模板快速应用
- 输入框 + 应用按钮
3. 多灯笼支持
技术难点:动态生成2-4个灯笼
function createLanterns() {
const count = config.lanternCount; // 2/3/4
const text = getFestivalText();
const chars = text.split('');
const configs = [
{ id: 'left', class: 'deng-box1', text: chars[0], pos: 'left' },
{ id: 'right', class: 'deng-box', text: chars[1], pos: 'right' },
];
if (count >= 3) {
configs.push({ id: 'center1', class: 'deng-box2', text: chars[2], pos: 'center' });
}
if (count >= 4) {
configs.push({ id: 'center2', class: 'deng-box3', text: chars[3], pos: 'center' });
}
// 动态生成 HTML
configs.forEach(cfg => {
const div = document.createElement('div');
div.innerHTML = `<div class="spring_lantern__${cfg.class}">...</div>`;
container.appendChild(div);
});
}
第三阶段:Bug 修复(重要!)
Bug #1: 右侧灯笼跑到屏幕左边 
现象:刷新页面后,右侧的灯笼消失了
排查过程:
- 检查 CSS 定位 - 看起来没问题
- 检查 HTML 结构 - 正常
- 使用开发者工具查看 - 发现灯笼在屏幕外
根本原因:
/* 错误的 CSS */
.spring_lantern__container {
position: fixed;
top: -20px;
/* ❌ 缺少 left/right/width */
}
.spring_lantern__deng-box {
position: absolute;
right: -20px; /* 相对于什么定位?容器没有宽度!*/
}
解决方案:
/* ✅ 正确的 CSS */
.spring_lantern__container {
position: fixed;
top: -20px;
left: 0;
right: 0;
width: 100%; /* 关键!*/
height: 0;
}
.spring_lantern__deng-box {
position: absolute;
right: -20px; /* 现在相对于整个屏幕 */
top: 0;
}
教训:使用 position: absolute 时,父容器必须有明确的定位上下文!
Bug #2: 控制面板开关不生效 
现象:点击开关没有任何反应
排查过程:
- 检查事件监听器 - 已绑定
- 检查选择器 - 正确
- 添加 console.log - 没有输出
根本原因:
// ❌ 错误的方式
panel.addEventListener('click', (e) => {
const switchEl = e.target.closest('.switch');
const action = switchEl.dataset.action; // ❌ 没有 data-action!
switch(action) {
case 'show': ...
}
});
// HTML 中
<div class="switch" data-action="show"> <!-- ✅ 这里是对的 -->
但实际上,我使用了 renderPanel() 重新生成 HTML,导致:
- 旧的事件监听器还在
- 但 HTML 元素已经被替换
- 新元素没有 data-action 属性!
解决方案:
// ✅ 使用 data-config 属性
panel.addEventListener('click', (e) => {
const switchEl = e.target.closest('.switch');
const configKey = switchEl.dataset.config; // ✅ 直接映射到 config
config[configKey] = !config[configKey];
applyConfig();
// 立即更新视觉状态
setTimeout(() => {
const updatedSwitch = panel.querySelector(`[data-config="${configKey}"]`);
updatedSwitch.classList.toggle('on', config[configKey]);
}, 0);
});
// HTML 中
<div class="switch" data-config="showLanterns"> <!-- ✅ 直接对应 config.showLanterns -->
核心技巧:使用事件委托 + data 属性,避免动态渲染时事件丢失
第四阶段:高级功能实现
1. 5种颜色主题
设计思路:
- 预定义5种配色方案
- 主题切换时重新生成 CSS
const colorThemes = {
traditional: {
name: '传统红',
suiLight: '#dc8f03',
suiDark: '#ffa500',
r1: 'rgba(216, 0, 15, 0.8)',
bgGradient: 'linear-gradient(135deg, #d8000f 0%, #ff4d4d 100%)',
},
gold: {
name: '金色年华',
suiLight: '#ffd700',
suiDark: '#daa520',
// ...
},
// ... purple, blue, rainbow
};
技术亮点:
- 动态生成 CSS,无需刷新页面
- 使用模板字符串插入颜色值
- 切换主题后立即生效
2. 节日自动切换
功能:根据日期自动更换灯笼文字
function getFestivalText() {
if (!config.autoTheme) return config.customText;
const now = new Date();
const month = now.getMonth() + 1;
const day = now.getDate();
// 春节
if (month === 1 && day >= 1 && day <= 15) return '迎春';
// 元宵节
if (month === 1 && day === 15) return '汤圆';
// 端午节
if (month === 6 && day >= 18 && day <= 25) return '安康';
// 中秋节
if (month === 9 && day >= 8 && day <= 15) return '团圆';
// 国庆
if (month === 10 && day >= 1 && day <= 7) return '国泰';
return config.customText;
}
3. 春节倒计时
技术点:计算距离下一个春节的天数
function getSpringCountdown() {
const now = new Date();
const year = now.getFullYear();
// 春节日期表(简化版,实际需要农历转换)
const springFestivals = {
2025: '2025-01-29',
2026: '2026-02-17',
2027: '2027-02-06',
// ...
};
let springDate = new Date(springFestivals[year] || `${year}-02-01`);
if (now > springDate) {
springDate.setFullYear(year + 1);
}
const diff = springDate - now;
return Math.ceil(diff / (1000 * 60 * 60 * 24));
}
4. 网站黑名单
功能:某些网站不显示灯笼
// 黑名单配置
config.blacklist = ['github.com', 'stackoverflow.com'];
// 检测当前网站
function isBlacklisted() {
const hostname = window.location.hostname;
return config.blacklist.some(domain => {
if (domain.startsWith('*.')) {
return hostname.endsWith(domain.slice(2));
}
return hostname === domain;
});
}
// 如果在黑名单,不渲染灯笼
if (isBlacklisted()) {
console.log('Lantern hidden: blacklisted');
return; // 退出脚本
}
最终效果展示
功能列表(17项)
视觉外观:
5种颜色主题
灯笼大小调节(0.5x - 1.5x)
位置调节(上下左右)
灯光闪烁效果
动画控制:
4种摆动模式
摆动速度调节
摆动幅度调节
动画连续性保持
内容功能:
支持2-4个灯笼
12个预设文字
自定义文字(1-4个汉字)
春节倒计时
节日自动切换
交互增强:
鼠标距离调节
双击灯笼切换
键盘快捷键(Ctrl+Shift+L/S/M)
实用功能:
网站黑名单
时间段控制
性能优化
技术实现亮点
1. 事件委托机制
问题:动态渲染 HTML 后,事件监听器失效
解决方案:
// ❌ 传统方式(会失效)
document.querySelectorAll('.switch').forEach(el => {
el.addEventListener('click', handler); // renderPanel 后失效
});
// ✅ 事件委托(始终有效)
panel.addEventListener('click', (e) => {
const switchEl = e.target.closest('.switch');
if (switchEl) {
const configKey = switchEl.dataset.config;
// 处理逻辑...
}
});
2. CSS 动态生成
问题:切换主题后如何立即生效?
解决方案:
// 重新生成所有 CSS
function updateStyles() {
const theme = getCurrentTheme();
style.innerHTML = `
.spring_lantern__deng {
background: ${theme.r1};
box-shadow: -5px 5px 50px 4px ${theme.deng_box_shadow};
/* ... */
}
.spring_lantern__panel-btn {
background: ${theme.bgGradient};
/* ... */
}
`;
}
优势:
- 无需刷新页面
- 立即生效
- 支持实时预览
3. 状态持久化
// 保存配置
function saveConfig() {
localStorage.setItem('spring_lantern_config_v2', JSON.stringify(config));
}
// 加载配置
const saved = localStorage.getItem('spring_lantern_config_v2');
if (saved) {
config = { ...defaultConfig, ...JSON.parse(saved) };
}
4. 性能优化
/* GPU 加速 */
.spring_lantern__deng {
will-change: transform; /* 提示浏览器优化 */
}
/* 平滑过渡 */
.spring_lantern__deng {
transition: opacity 0.4s ease-out,
transform 0.4s ease-out;
}
发布到 GitHub
仓库地址
GitHub - 9527wow/spring-lantern-enhanced: 🏮 春节灯笼油猴脚本 - 给所有网站挂上春节灯笼效果,支持完全自定义
文件结构
spring-lantern-enhanced/
├── spring-lantern-fixed.user.js # 主脚本(54KB)
├── README.md # 项目说明
└── LICENSE # MIT 许可证
安装方式
方式一:直接安装
- 访问:GitHub - 9527wow/spring-lantern-enhanced: 🏮 春节灯笼油猴脚本 - 给所有网站挂上春节灯笼效果,支持完全自定义
- 点击
spring-lantern-fixed.user.js - 点击 “Raw” 按钮
- Tampermonkey 会自动弹出安装提示
方式二:通过 Release
https://github.com/9527wow/spring-lantern-enhanced/releases/tag/v2.0.1
开发心得
遇到的坑
-
CSS 定位问题





- 教训:
position: absolute必须配合父容器的正确布局
- 教训:
-
事件监听器失效





- 教训:动态渲染的 HTML 必须使用事件委托
-
动画连续性




- 教训:不要用
display: none,要用opacity和transform
- 教训:不要用
-
CSS 动画性能



- 教训:使用
will-change触发 GPU 加速
- 教训:使用
收获与成长
-
CSS 动画能力提升
- 深入理解
animation-play-state - 掌握复杂的
keyframe动画 - 学会了
transform-origin的妙用
- 深入理解
-
JavaScript 工程化思维
- 配置管理(defaultConfig + userConfig)
- 状态持久化
- 事件委托的深入理解
-
用户体验设计
- 平滑的过渡动画
- 直观的控制面板
- 即时的预览反馈
使用指南
快速上手
- 安装脚本 - 见上方安装方式
- 访问任意网站 - 灯笼会自动出现
- 点击右下角灯笼按钮
- 打开控制面板 - 自定义设置:
- 选择颜色主题
- 调整灯笼大小和位置
- 输入自定义文字
- 开启/关闭各种效果
键盘快捷键
Ctrl+Shift+L- 显示/隐藏灯笼Ctrl+Shift+S- 停止/开始摆动Ctrl+Shift+M- 打开/关闭菜单
效果预览
默认配置下:
- 左侧灯笼:显示第一个字(如"迎")
- 右侧灯笼:显示第二个字(如"春")
- 颜色:传统红色
- 动画:轻轻摇摆
- 鼠标靠近:平滑淡出
未来规划
可以增加的功能
更多灯笼样式(宫灯、走马灯等)
自定义颜色(完全自定义RGB值)
音效(灯笼摇摆时的轻微风铃声)
移动端适配(针对手机屏幕优化)
多语言支持(英文、日文等)
总结
这个项目从一个小想法,经过几天的开发、调试、优化,最终变成了一个功能完善的油猴脚本。
开发时间:约4天
代码行数:1891行(主脚本)
功能数量:17项
Bug修复:3个
版本迭代:v1.0 → v2.0.1
致谢
感谢以下项目的启发:
- zggmd/spring-lantern - 灵感来源
- muzihuaner/deng - 原始设计
结尾
如果你也想让自己的浏览器充满节日氛围,欢迎试用这个脚本!
GitHub 仓库:GitHub - 9527wow/spring-lantern-enhanced: 🏮 春节灯笼油猴脚本 - 给所有网站挂上春节灯笼效果,支持完全自定义
直接安装:https://raw.githubusercontent.com/9527wow/spring-lantern-enhanced/main/spring-lantern-fixed.user.js
Star
支持:GitHub - 9527wow/spring-lantern-enhanced: 🏮 春节灯笼油猴脚本 - 给所有网站挂上春节灯笼效果,支持完全自定义
欢迎反馈 Bug 和功能建议!![]()
Happy Chinese New Year! ![]()
![]()
![]()