Butterfly 建站笔记(二):把分类与标签做成内容地图——数据快照、关联计算与前端筛选
Butterfly 默认的分类页和标签页能列出名称,但很难回答三个更实际的问题:这个分类最近写了什么、某个标签常和哪些标签一起出现、我能否直接搜索和排序?因此,这次改造把两个列表升级成了一张“内容地图”。 这不是单纯换一套 CSS。页面所需的大部分信息并不存在于原始模板中,必须先在 Hexo 构建阶段计算出来。 Hexo 生成网站时,会把文章、分类和标签放进本地数据模型: 这些对象看起来像数组,但实际可能是 Hexo 使用的查询集合。为了让后续代码统一处理,先写一个转换函数: 对新手来说,可以把它理解成一个“适配器”:不管 Hexo 交过来的数据是哪种包装,函数最终都返回普通数组。 分类总览、标签总览和每个详情页都需要文章数据。如果每渲染一个页面就重新统计一次,文章越多,构建时重复工作越多。因此脚本把计算结果缓存成快照: 一次 hexo generate 中,buildSnapshot() 只执行一次;下一次重新生成网站前清空缓存,确保新增文章能够进入统计。 快照中保存: Map 可以看作一本目录。使用分类名查找记录时,不必每次从数组第一项扫描到最后一项。 Hexo 知道分类名称和文章
Butterfly 建站笔记(三):重做文章归档——从时间分组到搜索、折叠与随机阅读
默认归档页解决了“按时间列出文章”,但文章多起来后仍不方便查找。这次重构保留 Hexo 原有归档路由,在其上增加年份折叠、月份分组、搜索、随机阅读和全站编号。 归档页要按完整年份折叠,就必须一次拿到全部文章。如果 Hexo 每页只交给脚本十篇文章,那么一个年份可能被拆到多页,脚本无法计算准确的年度数量。 因此 _config.yml 中单独关闭主归档分页: 这不会关闭首页分页。首页仍可使用: 两种配置服务于不同目标:主页需要控制首屏长度,归档页需要完整数据。 Hexo 还会生成 /archives/2026/、/archives/2026/07/ 等子页面。自定义脚本只改造第一页主归档: 这样,月份统计图等地方跳到具体年月时,仍能使用 Hexo 原生年月归档,不会被整站替换逻辑误伤。 构建阶段先按日期从新到旧排序,再用两个 Map 分组: 最终数据结构类似: 使用 Map 的好处是能保持插入顺序,也能用年份或月份直接找到分组。 页面按新到旧展示,但编号希望从最早文章开始累加。脚本先复制一份文章并改成从旧到新,再建立路径到编号的映射: 展示时通过文章路径取回编号,并补足位数: 最早的文章
Butterfly 建站笔记(一):让每次改变都有迹可循——更新记录页的设计与实现
一个持续维护的博客,从来不只是文章数量在增加。主题会升级,页面会重做,导航会调整,也会有许多只有站长自己知道的修复与取舍。 过去,这些变化散落在 Git 提交、配置文件和记忆里。访客只能看到今天的样子,却不知道它经历过什么;过一段时间后,连维护者自己也很难准确回答“这个功能是什么时候加上的”。因此,这次改造为博客增加了一个独立的更新记录页,把重要变化整理成一条可以回看的时间线。 这也是“Butterfly 建站笔记”系列的第一篇。本文不会只罗列最终代码,而是从构想、数据组织和渲染过程出发,完整记录这个页面是怎样被设计出来的。 最直接的做法,是新建一篇名为“更新记录”的 Markdown 文章,然后不断往下追加内容。但这种方案很快会遇到几个问题: 所以,这次改造没有把它做成普通文章,而是把它拆成了三个各司其职的部分: 页面文件 source/updates/index.md 反而非常轻,只保留页面配置和一个自定义标签: 这样,更新记录拥有固定的 /updates/ 地址,却不会被当作一篇普通博客文章。 改造前,博客的重要变化只能从提交记录或零散说明中寻找。它们对访客不可见,也缺少统一的归
Butterfly 建站笔记(五):移植 Eurkon 风格文章头部——DOM 增强、主色提取与动态波浪
Eurkon 的文章头部很有辨识度,但它是 Butterfly 的深度分支,整套覆盖会增加升级成本。本次只移植文章头部这一项:封面渐变、分类标签、动态波浪、主题色和评论统计,其余仍使用当前 Butterfly。 node_modules/hexo-theme-butterfly/ 中的文件会在重新安装依赖时被覆盖。如果直接改 Pug 模板,下一次 npm ci 或主题升级就需要重新合并。 这里采用“生成后增强”: 核心文件都在主题目录之外: 脚本默认效果名为 eurkon: 因此普通文章有封面就会启用。如果某篇文章不需要,在 Front Matter 中写: 文章还必须存在 top_img 或 cover: 没有图片时保留 Butterfly 原始头部,避免生成一个没有视觉主体的空效果。 过滤器先查找 Butterfly 已生成的头部: 匹配后增加: class 交给 CSS,data-* 交给浏览器脚本。构建阶段不需要知道图片最终应使用什么颜色。 长标题会额外获得类名: 使用 Array.from() 而不是普通字符串长度,对中文和部分 Unicode 字符更稳妥。 Butterfl
Butterfly 建站笔记(四):用 ECharts 看懂博客数据——统计页的数据生成与交互图表
统计页的难点不是调用 echarts.init(),而是把 Hexo 的文章模型整理成图表需要的数据,并确保图表只在统计页加载、能适应深色模式、窗口变化和 PJAX 页面切换。 项目中对应四个部分: Hexo 本身已经知道所有文章、标签和分类。如果浏览器打开页面后再请求接口,不但需要额外服务器,也会重复读取数据。 构建阶段直接获取本地模型: 统计结果会随每次 hexo generate 自动更新,线上仍然是纯静态页面。 如果只统计实际出现过的月份,没有发文的月份会消失,折线图横轴就不连续。例如一月发文、三月发文,不能把二月直接跳过。 脚本先从第一篇文章月份循环到当前月份,每个月填 0: 再遍历文章累加: 每个月还会附带归档地址: 所以点击折线上的有效数据点,可以直接进入当月归档。 标签数据先转换成 ECharts 常见的 { name, value } 结构: 浏览器端读取图表容器的 data-length="10",再截取前十个: 将数量统计和显示数量分开后,将来想改成 Top 15,只改页面属性即可。 Hexo 分类可以有父子层级。一篇文章可能同时带有父分类和子
Butterfly 建站笔记(六):首页摄影轮播——预加载、交叉淡入与缓存陷阱
首页轮播看起来只是定时换背景,但真正稳定的实现还要处理图片加载失败、淡入时的空白、后台标签页暂停绘制和浏览器缓存。本篇重点解释这些容易踩坑的细节。 把图片列表放进配置文件后,日常换图不需要编辑 JavaScript。 interval 使用毫秒,5000 表示 5 秒。脚本还会把过小的值限制在 3 秒以上: 太快的切换会让图片还没看清就消失,也会增加网络和绘制压力。 轮播依赖 JavaScript。如果脚本尚未执行或用户禁用了脚本,首页不能出现纯色空白。因此仍为 Butterfly 配置静态兜底图: 轮播初始化成功后再清除原背景: 这叫“渐进增强”:基础页面先可用,JavaScript 只在其上增加能力。 浏览器不能直接读取服务器上的 _config.butterfly.yml。Hexo 过滤器把必要配置写进 <head>: 只传给前端真正需要的两个字段,避免把整个主题配置暴露到页面。 如果只对一个元素执行: 浏览器会立即替换图片。CSS 很难同时保留上一张并让下一张淡入,图片没加载完时还可能短暂显示背景色。 这里采用“双层交叉淡入”: 每张图都是绝对定位的独立元素: 切换
Butterfly 建站笔记(七):把 Hexo 安全交给 GitHub Actions——构建校验、备份发布与缓存排查
博客迁移到 GitHub Actions 后,源码、构建结果和线上目录有了清晰边界。本篇不讨论按钮操作,重点解释一条可靠发布链路为什么要有锁、暂存目录、验证、备份和受保护文件。 线上目录不是源码仓库。直接修改服务器里的 HTML,下次部署会被构建结果覆盖;把 public/ 提交到 Git,也会同时维护源码和产物两份内容。 因此 .gitignore 忽略: 工作流监听 main 分支推送,也允许手工触发: 并发配置为: 同一时间只允许一条生产发布链路运行。cancel-in-progress: false 表示新提交不会在旧版本复制到一半时强行终止它,而是排队等待,避免线上目录处于半更新状态。 npm ci 严格按照 package-lock.json 安装。如果 package.json 和锁文件不一致会直接失败,不会悄悄选一个新版本。 对静态站来说,可重复构建很重要:同一个提交今天和下周构建,应该得到兼容的依赖组合。 删除上次生成的 public/,防止已经从源码删除的旧文件残留。 执行 hexo generate,把 Markdown、模板和数据转换为静态站。 构建成功只代表
转折
雨天总会让人有所思绪,平淡的日子里想起许久不曾更新的博客,拿出来记录一下这转折的半年。
蓝天碧海飞白鹭,波光远影泛渔舟——关于厦门的记忆
困在琐事许久,看海的心愈发难以压抑。聊城的考试结束后,来不及停留,火速乘坐动车前往与北方温差10°多的厦门。四天的鹭城旅途让人看够了海,并时时刻刻感受到来自厦门的浪漫。回校又疲于各种烦事,终于是有些许时间可以细细回忆,写下这篇旅途游记。 看海必来彩虹沙滩。即便是一夜动车,酒店放好东西后来不及休息,简单吃过午饭后直奔彩虹沙滩。这里不得不提一嘴厦门BRT,只有乘坐后才能理解那句话:“全国只有两种BRT,厦门BRT和其他BRT”。全程不堵车,平均速度大概40多,这才是真正意义上的快速公交。来到海边正是中午时刻,少有人影。这便是淡季旅行的优势——风景往往被自己一人承包。 随着海潮的涨起,我沿着海边,一路从彩虹沙滩看到乐海公园、嘉庚公园,许久以来心心念念、朝思暮想的大海,一下午算是看了个够。或许有时我喜爱的并不单纯是看海,更多的是享受这种吹拂海风、倾听海浪,给自己大脑一个完全沉溺于大自然而非烦于琐事的状态。上次这样沉溺已是一年以前——2024年9月底在滨海新区从妈祖园出来后夕阳下看海的时候。幻想过无数次在某个沿海城市定居,仿佛大海才会激起我对生活的向往,但往往唾手可得不会使人长久满足,只有保持适
十二月的寒冷
每年的十二月都在痛苦中熬过,今年更是如此。 不同在于少了往年的期末考试,却多了未曾有过的焦虑。国考前一夜彻夜未眠,想不清人生这条狭窄的路有怎样的最优路线。虽然常常安慰自己,眼前困难不算什么,或许很多年后想想也是“不过如此”。但当真正身处这样的时刻,很难控制自己做的到风轻云淡。记得在2020年疫情最严峻时,曾在某贴中看到有人戏称“这是过去十年最差的一年,却是未来十年最好的一年。”当时不以为然,直到如今切身经历就业的寒冬,才深刻体会到这句话的含金量。十二月的寒冬,呼啸的北风肆虐北方大地,带来一片荒凉;也带来就业的寒冷,席卷1000多万名应届毕业生的命运。社会看似给了很多出路和机会,但真正适合普通人的却少之又少,最终还是投向考公的红海。日本三十年前的老路,如今的我们正在原封不动地重新走过。 国考落下帷幕,慌慌张张参加山东省考,不出意外又是一败涂地。匆忙的行程、不断地腹泻以及异乡的孤独加深对这场考试的厌烦,但这就是这条路上的分岔口,是不是出口?谁也不知道。只有不断地试错、不断地摸索,才能迎来自己的光明。 很多人喜欢把考上研究生、考上公务员称之为“上岸”,我是极不认同的。当生活不断出现新的欲望,










