很久以前就想要这个功能了,今天借助豆包帮我实现了一下感谢豆包😄
网站全自动节日弹窗(纯前端实功能):
✅ 阳历节日+农历节日+二十四节气
✅ 仅当天首次访问弹出
✅ 淡入动画 + 关闭按钮
✅ 图片加载失败不弹窗
✅ 可直接放入 head 标签
实例截图

如果你是Halo用户 可以在Halo后台→设置→代码注入→全局Head标签 内插入下述代码
功能代码
此功能不依赖任何插件、不影响网站速度,弹窗优优先级:阳历 > 农历 > 节气
复制代码到网站 head 标签
替换图片地址为自己的海报
<style>
/* 节日弹窗样式 */
.festival-popup {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
z-index: 999999;
cursor: pointer;
opacity: 0;
animation: fadeIn 0.3s forwards;
}
/* 海报图片样式 */
.festival-popup img {
max-width: 90%;
max-height: 90vh;
object-fit: contain;
border-radius: 12px;
}
/* 关闭按钮 × */
.close-btn {
position: absolute;
top: 20px;
right: 20px;
width: 44px;
height: 44px;
background: rgba(0, 0, 0, 0.5);
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
}
/* 淡入动画 */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
// ==========================
// 🎨 在这里替换你的海报图片
// ==========================
// 阳历节日
const solarList = [
{ name: "元旦", img: "https://picsum.photos/id/1/800/1000" },
{ name: "情人节", img: "https://picsum.photos/id/2/800/1000" },
{ name: "妇女节", img: "https://picsum.photos/id/3/800/1000" },
{ name: "愚人节", img: "https://picsum.photos/id/4/800/1000" },
{ name: "劳动节", img: "https://picsum.photos/id/5/800/1000" },
{ name: "儿童节", img: "https://picsum.photos/id/6/800/1000" },
{ name: "教师节", img: "https://picsum.photos/id/7/800/1000" },
{ name: "国庆节", img: "https://picsum.photos/id/8/800/1000" },
{ name: "双十一", img: "https://picsum.photos/id/9/800/1000" },
{ name: "圣诞节", img: "https://picsum.photos/id/10/800/1000" }
];
// 农历节日
const lunarList = [
{ name: "春节", img: "https://picsum.photos/id/11/800/1000" },
{ name: "元宵节", img: "https://picsum.photos/id/12/800/1000" },
{ name: "端午节", img: "https://picsum.photos/id/13/800/1000" },
{ name: "七夕节", img: "https://picsum.photos/id/14/800/1000" },
{ name: "中秋节", img: "https://picsum.photos/id/15/800/1000" },
{ name: "重阳节", img: "https://picsum.photos/id/16/800/1000" }
];
// 二十四节气
const solarTermsList = [
{ name: "立春", img: "https://picsum.photos/id/17/800/1000" },
{ name: "雨水", img: "https://picsum.photos/id/18/800/1000" },
{ name: "惊蛰", img: "https://picsum.photos/id/19/800/1000" },
{ name: "春分", img: "https://picsum.photos/id/20/800/1000" },
{ name: "清明", img: "https://picsum.photos/id/21/800/1000" },
{ name: "谷雨", img: "https://picsum.photos/id/22/800/1000" },
{ name: "立夏", img: "https://picsum.photos/id/23/800/1000" },
{ name: "小满", img: "https://picsum.photos/id/24/800/1000" },
{ name: "芒种", img: "https://picsum.photos/id/25/800/1000" },
{ name: "夏至", img: "https://picsum.photos/id/26/800/1000" },
{ name: "小暑", img: "https://picsum.photos/id/27/800/1000" },
{ name: "大暑", img: "https://picsum.photos/id/28/800/1000" },
{ name: "立秋", img: "https://picsum.photos/id/29/800/1000" },
{ name: "处暑", img: "https://picsum.photos/id/30/800/1000" },
{ name: "白露", img: "https://picsum.photos/id/31/800/1000" },
{ name: "秋分", img: "https://picsum.photos/id/32/800/1000" },
{ name: "寒露", img: "https://picsum.photos/id/33/800/1000" },
{ name: "霜降", img: "https://picsum.photos/id/34/800/1000" },
{ name: "立冬", img: "https://picsum.photos/id/35/800/1000" },
{ name: "小雪", img: "https://picsum.photos/id/36/800/1000" },
{ name: "大雪", img: "https://picsum.photos/id/37/800/1000" },
{ name: "冬至", img: "https://picsum.photos/id/38/800/1000" },
{ name: "小寒", img: "https://picsum.photos/id/39/800/1000" },
{ name: "大寒", img: "https://picsum.photos/id/40/800/1000" }
];
// ==========================
// 🔧 下方为系统逻辑,请勿修改
// ==========================
const solarMap = {
"元旦": "01-01", "情人节": "02-14", "妇女节": "03-08", "愚人节": "04-01",
"劳动节": "05-01", "儿童节": "06-01", "教师节": "09-10", "国庆节": "10-01",
"双十一": "11-11", "圣诞节": "12-25"
};
const lunarMap = {
"春节": "01-01", "元宵节": "01-15", "端午节": "05-05",
"七夕节": "07-07", "中秋节": "08-15", "重阳节": "09-09"
};
// 获取农历日期
function getLunarDate(date) {
const lunarInfo = [0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,0x0e950,0x06aa0,0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b5a0,0x195a6,0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0];
const solarMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
function isLeapYear(y) { return (y%4==0&&y%100!=0)||(y%400==0); }
function lYearDays(y) { let sum=348; for(let i=0x8000;i>0x8;i>>=1) sum+=(lunarInfo[y-1900]&i)?1:0; return sum+leapDays(y); }
function leapMonth(y) { return lunarInfo[y-1900]&0xf; }
function leapDays(y) { return leapMonth(y)?(lunarInfo[y-1900]&0x10000?30:29):0; }
function monthDays(y,m){ return lunarInfo[y-1900]&(0x10000>>m)?30:29; }
let y = date.getFullYear(), m = date.getMonth(), d = date.getDate();
if(y<1900||y>2100) return null;
let total = 0;
for(let i=1900;i<y;i++) total+=lYearDays(i);
if(isLeapYear(y)&&m>1) total++;
for(let i=0;i<m;i++) total+=solarMonth[i]; total+=d;
let ly=1900; while(total>lYearDays(ly)){ total-=lYearDays(ly); ly++; }
let lm=1,leap=leapMonth(ly),isLeap=false;
while(true){
let md=monthDays(ly,lm,lunarInfo);
if(leap&&lm==leap&&!isLeap){ md=leapDays(ly); isLeap=true; }
else{ if(total<=md) break; total-=md; lm++; isLeap=false; }
}
return `${String(lm).padStart(2,"0")}-${String(total).padStart(2,"0")}`;
}
// 获取节气
function getSolarTerm(date){
const terms = ["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"];
const baseDate = new Date(2000,0,6,2,5,0);
const ts = (Date.UTC(date.getFullYear(),date.getMonth(),date.getDate()) - baseDate.getTime()) / 86400000;
return terms[Math.floor((ts + 21.16) / 15.218425) % 24];
}
// 获取今天信息
const today = new Date();
const solarKey = `${String(today.getMonth()+1).padStart(2,0)}-${String(today.getDate()).padStart(2,0)}`;
const lunarKey = getLunarDate(today);
const currentTerm = getSolarTerm(today);
const storageKey = `popup_${solarKey}`;
// 优先级匹配:阳历 → 农历 → 节气
let todayImage = null;
for (let item of solarList) { if (solarMap[item.name] === solarKey) { todayImage = item.img; break; } }
if (!todayImage && lunarKey) { for (let item of lunarList) { if (lunarMap[item.name] === lunarKey) { todayImage = item.img; break; } } }
if (!todayImage) { for (let item of solarTermsList) { if (item.name === currentTerm) { todayImage = item.img; break; } } }
// 弹出逻辑(图片加载成功才显示)
if (todayImage && !localStorage.getItem(storageKey)) {
const popup = document.createElement("div");
popup.className = "festival-popup";
const img = new Image();
img.src = todayImage;
img.onload = function () {
popup.innerHTML = `<img src="${todayImage}" alt="节日海报"><div class="close-btn">×</div>`;
document.body.appendChild(popup);
// 点击背景关闭
popup.onclick = function (e) {
if (e.target === popup) {
popup.remove();
localStorage.setItem(storageKey, "1");
}
};
// 点击×关闭
popup.querySelector(".close-btn").onclick = function () {
popup.remove();
localStorage.setItem(storageKey, "1");
};
};
}
});
</script>注:封面图片来源于摄图网‘老卢’已获取此图的VRF授权(图片ID:330153954)