--- title: 在侧边栏添加日历和倒计时 categories: 建站手札 cover: https://pic.biss.click/image/232af9c6-97ce-42f8-85a8-9338963066e6.webp tags: 网站 series: webcustom summary: 实现了一个侧边栏日历与倒计时卡片,包含以下核心功能:日历展示:显示当前日期(公历与农历)、星期、生肖、干支年份。动态生成当月日历网格,高亮当天日期。倒计时模块:距离除夕倒计时:实时计算并显示剩余天数(示例中为2026年2月16日)。进度条:分别展示本年、本月、本周的已过去进度(百分比)及剩余天数。农历支持:调用 chinese-lunar.js 库将公历转换为农历,格式化显示为“干支年+生肖年+农历月+农历日”。 abbrlink: 5ed2f1e6 date: 2026-01-16T15:47:07+08:00 --- 突然看到某个网站侧边栏有日历和倒计时,就研究了一下,抄下来了(🤭) 效果图:
效果图
# 添加js ```js document.addEventListener("DOMContentLoaded", () => { initializeCard(); }); document.addEventListener("pjax:complete", () => { initializeCard(); }); function initializeCard() { cardTimes(); cardRefreshTimes(); } let year, month, week, date, dates, weekStr, monthStr, asideTime, asideDay, asideDayNum, animalYear, ganzhiYear, lunarMon, lunarDay; const now = new Date(); function cardRefreshTimes() { const e = document.getElementById("card-widget-schedule"); if (e) { asideDay = (now - asideTime) / 1e3 / 60 / 60 / 24; e.querySelector("#pBar_year").value = asideDay; e.querySelector("#p_span_year").innerHTML = (asideDay / 365 * 100).toFixed(1) + "%"; e.querySelector(".schedule-r0 .schedule-d1 .aside-span2").innerHTML = `还剩 ${(365 - asideDay).toFixed(0)} 天`; e.querySelector("#pBar_month").value = date; e.querySelector("#pBar_month").max = dates; e.querySelector("#p_span_month").innerHTML = (date / dates * 100).toFixed(1) + "%"; e.querySelector(".schedule-r1 .schedule-d1 .aside-span2").innerHTML = `还剩 ${(dates - date)} 天`; e.querySelector("#pBar_week").value = week === 0 ? 7 : week; e.querySelector("#p_span_week").innerHTML = ((week === 0 ? 7 : week) / 7 * 100).toFixed(1) + "%"; e.querySelector(".schedule-r2 .schedule-d1 .aside-span2").innerHTML = `还剩 ${(7 - (week === 0 ? 7 : week))} 天`; } } function cardTimes() { year = now.getFullYear(); month = now.getMonth(); week = now.getDay(); date = now.getDate(); const e = document.getElementById("card-widget-calendar"); if (e) { const isLeapYear = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; weekStr = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"][week]; const monthData = [ { month: "1月", days: 31 }, { month: "2月", days: isLeapYear ? 29 : 28 }, { month: "3月", days: 31 }, { month: "4月", days: 30 }, { month: "5月", days: 31 }, { month: "6月", days: 30 }, { month: "7月", days: 31 }, { month: "8月", days: 31 }, { month: "9月", days: 30 }, { month: "10月", days: 31 }, { month: "11月", days: 30 }, { month: "12月", days: 31 } ]; monthStr = monthData[month].month; dates = monthData[month].days; const t = (week + 8 - date % 7) % 7; let n = "", d = false, s = 7 - t; const o = (dates - s) % 7 === 0 ? Math.floor((dates - s) / 7) + 1 : Math.floor((dates - s) / 7) + 2; const c = e.querySelector("#calendar-main"); const l = e.querySelector("#calendar-date"); l.style.fontSize = ["64px", "48px", "36px"][Math.min(o - 3, 2)]; for (let i = 0; i < o; i++) { if (!c.querySelector(`.calendar-r${i}`)) { c.innerHTML += `
`; } for (let j = 0; j < 7; j++) { if (i === 0 && j === t) { n = 1; d = true; } const r = n === date ? " class='now'" : ""; if (!c.querySelector(`.calendar-r${i} .calendar-d${j} a`)) { c.querySelector(`.calendar-r${i}`).innerHTML += `
${n}
`; } if (n >= dates) { n = ""; d = false; } if (d) { n += 1; } } } const lunarDate = chineseLunar.solarToLunar(new Date(year, month, date)); animalYear = chineseLunar.format(lunarDate, "A"); ganzhiYear = chineseLunar.format(lunarDate, "T").slice(0, -1); lunarMon = chineseLunar.format(lunarDate, "M"); lunarDay = chineseLunar.format(lunarDate, "d"); const newYearDate = new Date("2026/02/16 00:00:00"); const daysUntilNewYear = Math.floor((newYearDate - now) / 1e3 / 60 / 60 / 24); asideTime = new Date(`${new Date().getFullYear()}/01/01 00:00:00`); asideDay = (now - asideTime) / 1e3 / 60 / 60 / 24; asideDayNum = Math.floor(asideDay); const weekNum = week - asideDayNum % 7 >= 0 ? Math.ceil(asideDayNum / 7) : Math.ceil(asideDayNum / 7) + 1; e.querySelector("#calendar-week").innerHTML = `第${weekNum}周 ${weekStr}`; e.querySelector("#calendar-date").innerHTML = date.toString().padStart(2, "0"); e.querySelector("#calendar-solar").innerHTML = `${year}年${monthStr} 第${asideDay.toFixed(0)}天`; e.querySelector("#calendar-lunar").innerHTML = `${ganzhiYear}${animalYear}年 ${lunarMon}${lunarDay}`; document.getElementById("schedule-days").innerHTML = daysUntilNewYear; } } ``` # 添加css 在主题文件 `source/css/`新建 `calendar.css`。 ```css /* 浅色主题变量覆盖 -------------------------------- */ :root { --anzhiyu-main: #a0d2eb; /* 主强调色:柔和天空蓝 */ --anzhiyu-main-op: rgba(160, 210, 235, 0.6); --anzhiyu-main-op-deep: rgba(160, 210, 235, 0.4); --anzhiyu-main-op-light: rgba(160, 210, 235, 0.2); --efu-card-bg: #fdfdfd; /* 卡片背景:几乎白 */ --efu-fontcolor: #444; /* 主文本:深灰 */ --efu-secondtext: #999; /* 次级文本:浅灰 */ } .card-widget { padding: 10px!important; max-height: calc(100vh - 100px); } .card-times a, .card-times div { color: var(--efu-fontcolor); } #card-widget-calendar .item-content { display: flex; } #calendar-area-left { width: 45%; } #calendar-area-right { width: 55%; } #calendar-area-left, #calendar-area-right { height: 100%; padding: 8px; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; } #calendar-main { width: 100%; } #calendar-week { height: 1.2rem; font-size: 14px; letter-spacing: 1px; font-weight: 700; align-items: center; display: flex; } #calendar-date { height: 3rem; line-height: 1.3; font-size: 64px; letter-spacing: 3px; color: var(--anzhiyu-main); font-weight: 700; align-items: center; display: flex; position: relative; top: calc(50% - 2.1rem); } #calendar-lunar, #calendar-solar { height: 1rem; font-size: 12px; align-items: center; display: flex; position: absolute; } #calendar-solar { bottom: 2.1rem; } #calendar-lunar { bottom: 1rem; color: var(--efu-secondtext); } #calendar-main a { height: 1rem; width: 1rem; border-radius: 50%; font-size: 12px; line-height: 12px; display: flex; justify-content: center; align-items: center; } #calendar-main a.now { background: var(--anzhiyu-main); color: var(--efu-card-bg); } #calendar-main .calendar-rh a { color: var(--efu-secondtext); } .calendar-r0, .calendar-r1, .calendar-r2, .calendar-r3, .calendar-r4, .calendar-r5, .calendar-rh { height: 1.2rem; display: flex; } .calendar-d0, .calendar-d1, .calendar-d2, .calendar-d3, .calendar-d4, .calendar-d5, .calendar-d6 { width: calc(100% / 7); display: flex; justify-content: center; align-items: center; } #card-widget-schedule .item-content { display: flex; } #schedule-area-left, #schedule-area-right { height: 100px; display: flex; flex-direction: column; justify-content: center; align-items: center; } #schedule-area-left { width: 30%; } #schedule-area-right { width: 70%; padding: 0 5px; } .schedule-r0, .schedule-r1, .schedule-r2 { height: 2rem; width: 100%; align-items: center; display: flex; } .schedule-d0 { width: 30px; margin-right: 5px; text-align: center; font-size: 12px; } .schedule-d1 { width: calc(100% - 35px); height: 1.5rem; align-items: center; display: flex; } progress::-webkit-progress-bar { background: linear-gradient(to right, var(--anzhiyu-main-op-deep), var(--anzhiyu-main-op), var(--anzhiyu-main-op-light)); border-radius: 5px; overflow: hidden; } progress::-webkit-progress-value { background: var(--anzhiyu-main); border-radius: 5px; } .aside-span1, .aside-span2 { height: 1rem; font-size: 12px; z-index: 1; display: flex; align-items: center; position: absolute; } .aside-span1 { margin-left: 5px; } .aside-span2 { right: 20px; color: var(--efu-secondtext); } .aside-span2 a { margin: 0 3px; } #pBar_month, #pBar_week, #pBar_year { width: 100%; border-radius: 5px; height: 100%; } #schedule-date, #schedule-days, #schedule-title { display: flex; align-items: center; } #schedule-title { height: 25px; line-height: 1; font-size: 14px; font-weight: 700; } #schedule-days { height: 40px; line-height: 1; font-size: 30px; font-weight: 900; color: var(--anzhiyu-main); } #schedule-date { height: 20px; line-height: 1; font-size: 12px; color: var(--efu-secondtext); } ``` # 引入 新增+号后面内容 ```yml inject: head: # 自定义css + - bottom: # 自定义js + - + - ``` 在 `blogroot/source/_data` 文件夹下创建 `widget.yml` 文件,并添加以下内容: ```yml bottom: - class_name: calendar id_name: card-widget-calendar name: icon: order: -1 html: |
- class_name: schedule id_name: card-widget-schedule name: icon: order: -1 html: |
距离除夕
2025-01-28
本年
还剩
本月
还剩
本周
还剩
``` # 参考 {% link 乐活星球,lohas,https://blog.lohas.fun/hc/jc005/ %}