
前段时间,偶然发现一篇博文,大意就是关于给 Hexo 博客的侧边栏添加一个倒计时,虽然此功能在一些 PHP 博客中已经是常见功能,但是在 hexo 博客之中还是比较少见的,难能可贵的是这个小功能可以非常方便的迁移到安知鱼主题上,详细操作过程如下:
1.添加、引用 JavaScript
首先我们需要为日历卡片进行逻辑实现和样式定义,需要大家进入到博客根目录的主题文件夹内。
在博客主题的 /source/ 目录中的 js 文件夹中创建一个名为 countdown.js 的文件。在新建的 countdown.js 文件中添加以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
| const CountdownTimer = (() => { const config = { targetDate: "2026-02-17", /* 这里记得每年更新春节日期 */ targetName: "春节", units: { day: { text: "今日", unit: "小时" }, week: { text: "本周", unit: "天" }, month: { text: "本月", unit: "天" }, year: { text: "本年", unit: "天" } } };
const calculators = { day: () => { const hours = new Date().getHours(); return { remaining: 24 - hours, percentage: (hours / 24) * 100 }; }, week: () => { const day = new Date().getDay(); const passed = day === 0 ? 6 : day - 1; return { remaining: 6 - passed, percentage: ((passed + 1) / 7) * 100 }; }, month: () => { const now = new Date(); const total = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate(); const passed = now.getDate() - 1; return { remaining: total - passed, percentage: (passed / total) * 100 }; }, year: () => { const now = new Date(); const start = new Date(now.getFullYear(), 0, 1); const total = 365 + (now.getFullYear() % 4 === 0 ? 1 : 0); const passed = Math.floor((now - start) / 86400000); return { remaining: total - passed, percentage: (passed / total) * 100 }; } };
function updateCountdown() { const elements = ['eventName', 'eventDate', 'daysUntil', 'countRight'] .map(id => document.getElementById(id));
if (elements.some(el => !el)) return;
const [eventName, eventDate, daysUntil, countRight] = elements; const now = new Date(); const target = new Date(config.targetDate);
eventName.textContent = config.targetName; eventDate.textContent = config.targetDate; daysUntil.textContent = Math.round((target - now.setHours(0,0,0,0)) / 86400000);
countRight.innerHTML = Object.entries(config.units) .map(([key, {text, unit}]) => { const {remaining, percentage} = calculators[key](); return ` <div class="cd-count-item"> <div class="cd-item-name">${text}</div> <div class="cd-item-progress"> <div class="cd-progress-bar" style="width: ${percentage}%; opacity: ${percentage/100}"></div> <span class="cd-percentage ${percentage >= 46 ? 'cd-many' : ''}">${percentage.toFixed(2)}%</span> <span class="cd-remaining ${percentage >= 60 ? 'cd-many' : ''}"> <span class="cd-tip">还剩</span>${remaining}<span class="cd-tip">${unit}</span> </span> </div> </div> `; }).join(''); }
function injectStyles() { const styles = ` .card-countdown .item-content { display: flex; } .cd-count-left { position: relative; display: flex; flex-direction: column; margin-right: 0.8rem; line-height: 1.5; align-items: center; justify-content: center; } .cd-count-left .cd-text { font-size: 14px; } .cd-count-left .cd-name { font-weight: bold; font-size: 18px; } .cd-count-left .cd-time { font-size: 30px; font-weight: bold; color: var(--anzhiyu-main); } .cd-count-left .cd-date { font-size: 12px; opacity: 0.6; } .cd-count-left::after { content: ""; position: absolute; right: -0.8rem; width: 2px; height: 80%; background-color: var(--anzhiyu-main); opacity: 0.5; } .cd-count-right { flex: 1; margin-left: .8rem; display: flex; flex-direction: column; justify-content: space-between; } .cd-count-item { display: flex; flex-direction: row; align-items: center; height: 24px; } .cd-item-name { font-size: 14px; margin-right: 0.8rem; white-space: nowrap; } .cd-item-progress { position: relative; display: flex; flex-direction: row; align-items: center; justify-content: space-between; height: 100%; width: 100%; border-radius: 8px; background-color: var(--anzhiyu-background); overflow: hidden; } .cd-progress-bar { height: 100%; border-radius: 8px; background-color: var(--anzhiyu-main); } .cd-percentage, .cd-remaining { position: absolute; font-size: 12px; margin: 0 6px; transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; } .cd-many { color: #fff; } .cd-remaining { opacity: 0; transform: translateX(10px); } .card-countdown .item-content:hover .cd-remaining { transform: translateX(0); opacity: 1; } .card-countdown .item-content:hover .cd-percentage { transform: translateX(-10px); opacity: 0; } `;
const styleSheet = document.createElement("style"); styleSheet.textContent = styles; document.head.appendChild(styleSheet); }
let timer; const start = () => { injectStyles(); updateCountdown(); timer = setInterval(updateCountdown, 600000); };
['pjax:complete', 'DOMContentLoaded'].forEach(event => document.addEventListener(event, start)); document.addEventListener('pjax:send', () => timer && clearInterval(timer));
return { start, stop: () => timer && clearInterval(timer) }; })();
|
大家注意上面的代码第三行
1
| targetDate: "2026-02-17", /* 这里记得每年更新春节日期 */
|
每年需要手动更新一下日期,如果忘记更新的话,年月日倒计时功能不受影响,只是距离春节天数会变为负数。
从上面的代码可以看到,已经包含基本 CSS 样式,无需另外添加新 CSS 文件,然后是引入这个 JS 文件。
2.引入JavaScript文件
在安知鱼主题的配置文件中搜索 inject ,就会找到如下代码
1 2 3 4 5 6 7 8 9 10 11
| # Inject # Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag) # 插入代码到头部 </head> 之前 和 底部 </body> 之前 inject: head: # 自定义css # - <link rel="stylesheet" href="/css/custom.css" media="defer" onload="this.media='all'">
bottom: # 自定义js # - <script src="/js/xxx"></script>
|
在 bottom 处进行自定义 js 的引入工作:
1
| - <script src="/js/countdown.js"></script>
|
修改完之后的代码
1 2 3 4 5 6 7 8 9 10 11 12
| # Inject # Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag) # 插入代码到头部 </head> 之前 和 底部 </body> 之前 inject: head: # 自定义css # - <link rel="stylesheet" href="/css/custom.css" media="defer" onload="this.media='all'">
bottom: # 自定义js # - <script src="/js/xxx"></script> - <script src="/js/countdown.js"></script>
|
在博客的 /source/ 目录中的 _data 文件夹中创建一个名为 widget.yml 的文件。
多说一句,**_data** 文件夹是一个数据存储目录,一般情况是用来存放网站的各种结构化数据。
如果你没有 _data 文件夹,可以自行创建一个。
目录和文件创建好后,在 widget.yml 文件中添加以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13
| top: - class_name: card-countdown id_name: name: icon: html: | <div class="cd-count-left"> <span class="cd-text">距离</span> <span class="cd-name" id="eventName"></span> <span class="cd-time" id="daysUntil"></span> <span class="cd-date" id="eventDate"></span> </div> <div id="countRight" class="cd-count-right"></div>
|
4.结束语
最后 Hexo 三板斧,就可以在页面侧边栏查看效果。欢迎大家在评论区给予指正,让我们共同打造快节奏时代,不受算法牵制的属于我们自己的小空间!