Butterfly 建站笔记(一):从零搭建一个可折叠的更新记录页
博客维护一段时间后,页面样式、主题版本、导航结构和部署方式都会不断变化。如果这些修改只留在 Git 提交里,访客看不到,自己过几个月也很难快速回忆。于是我为 Butterfly 博客增加了一个独立的“更新记录”页面:它按年份折叠、按日期排列,并用不同颜色区分“新增、优化、修复、升级”等类型。 这篇文章不再只解释设计思路,而是从一个空页面开始,带你依次创建页面入口、YAML 数据、Hexo 渲染脚本和 CSS 样式。完成后,你会得到一个固定地址为 /updates/、可以长期维护的更新记录页。 下面的交互演示器用于直观呈现“文件怎样逐步增加、页面怎样逐步成形”。它不会在浏览器中真正运行 Hexo;真正的生成与检查仍需在 Hexo 项目目录执行本文给出的命令。 点击演示器中的“上一步”“下一步”或左侧步骤,可以从空白页面一直看到最终时间线。右上角还可以切换桌面/手机宽度和浅色/深色预览。 整个功能由四个核心文件组成: 它们之间的关系很简单:updates.yml 保存内容,blog-updates.js 把内容转换成 HTML,blog-updates.css 负责外观
Butterfly 建站笔记(二):从零搭建分类与标签内容地图
Butterfly 默认的分类页和标签页可以列出名称与文章数量,但很难直接回答“这个分类最近写了什么”“某个标签经常和哪些标签一起出现”“能不能在当前页面搜索与排序”。本篇将从默认列表开始,一步一步把分类与标签改造成一张内容地图。 完成后,分类总览会显示说明、图标、颜色、最近文章和十二个月活跃度;标签总览会支持即时搜索、热度排序、最近使用排序和关联标签;分类与标签详情页也会获得统一的文章列表和横向导航。 交互演示负责展示文件与页面如何逐步变化,并不会在访客浏览器中执行 Hexo。真实数据统计仍在 hexo generate 阶段完成。 本次改造包含四个核心文件: 先确认分类页和标签页已经存在: 它们通常分别包含: 在修改前执行一次: 保证原有分类、标签和详情页能够正常生成。不要直接修改 public/categories/、public/tags/ 或主题依赖中的模板。 Hexo 知道分类名称和文章数量,却不知道“建站笔记应该使用代码图标和蓝色”。在 source/_data 中新建 taxonomy.yml: 字段含义如下: 普通标签不需要写进 YAML,它们仍然从文章 Front
Butterfly 建站笔记(三):从零重做可搜索、可折叠的文章归档
Butterfly 默认归档能够按时间显示文章,但文章变多后会遇到三个问题:分页把完整时间线切开、无法在当前页搜索全部文章、年份和月份缺少统一的折叠与数量反馈。本篇从关闭归档分页开始,逐步建立年份、月份、稳定编号、全文筛选和随机阅读。 本文只接管 /archives/ 主归档页。年度归档、月度归档、分类和标签分页继续由 Hexo 原生成器处理。 项目文件分工如下: 打开站点 _config.yml,找到归档生成器配置: per_page: 0 的作用是让主归档页面在构建时拿到全部文章。若仍保留每页十篇,浏览器端搜索只能搜索当前分页,无法实现真正的完整归档。 修改后执行: 确认 /archives/ 中已经包含全部文章,再继续编写接管脚本。 新建 scripts/blog-archives.js,先写基础工具: 过滤器中要严格限制页面: 这样 /archives/2026/ 和 /archives/2026/07/ 不会被重复接管。 文章日期可能来自不同环境。如果构建服务器使用 UTC,本地使用上海时区,临近午夜的文章可能被分进不同月份。站点 _config.yml 应设置: 格式化时优
Butterfly 建站笔记(四):从零搭建 ECharts 博客统计页
文章数量、标签热度和分类分布都存在于 Hexo 数据中,但普通页面无法直观看出发布节奏。本篇从一个空白 /charts/ 页面开始,在构建阶段统计月份、标签和分类,再使用站内 ECharts 生成折线图、横向柱状图和分类图。 在博客根目录安装: 确认 package.json 和 package-lock.json 都发生变化。不要只引用公共 CDN,否则离线预览、国内网络和第三方可用性都会成为额外故障点。 新建 source/charts/index.md: 统计页拥有固定地址,不会进入首页文章列表。 新建 scripts/blog-charts.js: 这一步只把 Hexo 查询集合转成普通数组,后续统计才不会依赖内部实现。 先累计实际出现的月份: 只有这一步还不够。如果某个月没有文章,它会直接从横轴消失。需要根据最早和最晚文章建立连续月份: 最终得到: 第二排序条件很重要:文章数相同的标签按中文名称稳定排序,避免每次构建顺序变化。 分类可能有父子关系,不能只把它当作一维数组: 如果只需要扁平玫瑰图,也可以把叶子节点展开后统计;保留树结构则可以使用旭日图展示上下级关系。 不要直接把
Butterfly 建站笔记(五):从零实现 Eurkon 风格文章头部
Eurkon 风格文章头部的吸引力来自封面主色、标题层级、分类标签和动态波浪,但直接迁移整套主题会与现有 Butterfly 定制发生大量冲突。本篇采用“增强层”方案:保留 Butterfly 原模板,在构建期只给文章页注入资源,再由浏览器重组现有 DOM。 这不是完整 Eurkon 主题迁移,也不修改 node_modules/hexo-theme-butterfly/。以后升级 Butterfly 时,站点级增强文件仍然独立存在。 不要编辑: 依赖升级会覆盖这里的修改。我们只读取 Butterfly 已经生成的结构,例如: 新建 scripts/post-header-effect.js: 这样分类页、标签页和普通独立页不会加载文章头部资源。 新建 source/js/post-header-eurkon.js: data-eurkon-bound 防止 PJAX 多次进入文章时重复添加封面和波浪。 不要重新生成另一套标题,而是移动原节点: 真实站点中,分类和标签选择器要根据当前 Butterfly 输出确认。若找不到某个节点,跳过即可,不要让整个标题消失。 背景图不方便做取色、解
Butterfly 建站笔记(六):从零搭建稳定的首页摄影轮播
Butterfly 的 index_img 适合一张首页背景,但摄影博客往往希望轮换多张作品。简单定时修改 background-image 会出现蓝色空档、坏图卡死、切回后台标签后突然连跳,以及线上缓存仍执行旧代码等问题。本篇从保留默认图开始,逐步实现预加载、双图层交叉淡入和缓存版本管理。 打开 _config.butterfly.yml: 不要把默认图删掉。轮播 JavaScript 未加载、配置为空或所有图片失败时,它仍是可见背景。 在同一配置文件加入: 建议切换间隔不少于 5 秒,过快会分散阅读注意力,也增加图片请求频率。 新增图片时先保留上一张已经验证可用的图,确认新图正常加载后再删除旧图。 浏览器无法直接读取 YAML。新建 scripts/home-banner-config.js: 只向首页写入数据: 不要把轮播配置注入每一篇文章。 新建 source/js/home-banner-carousel.js: 为什么不用一个元素直接换背景?因为浏览器需要下载并解码新图。单层在这个间隙可能露出 Butterfly 原背景色;双层可以让旧图持续可见。 样式可以放进 sourc
Butterfly 建站笔记(七):从零搭建可回滚的 GitHub Actions 部署
Hexo 自动部署不只是“构建后把 public 复制到服务器”。如果直接覆盖正式目录,上传中断、两个工作流并发或构建产物不完整,都可能让线上网站进入半更新状态。本篇从源码仓库开始,逐步建立依赖锁定、构建验证、临时上传、部署锁、备份激活和缓存排查。 本文中的服务器用户名、地址和目录都是示例。SSH 私钥必须保存到 GitHub Secrets,不要写进仓库、文章或日志。 不要在服务器正式目录中直接运行 Hexo,也不要把服务器目录当作源码仓库。 package.json 至少提供: 提交 package-lock.json,并在本地验证: npm ci 严格按照锁文件安装;依赖声明与锁文件不一致时直接失败,比自动修改依赖树更适合 CI。 只检查 hexo generate 退出码不够。可以在 tools/verify-build.mjs 检查: 项目还可以继续验证本地 JS/CSS 引用、空白页面、关键自定义模块和构建日志中的 ERROR、FATAL。 新建 .github/workflows/deploy.yml: concurrency 防止两个提交同时激活不同版本,但服
Butterfly 建站笔记(八):从零搭建旅行相册足迹地图
普通相册只能回答“拍了什么”,地图则能回答“去过哪里”。本篇从一份 gallery.yml 开始,把省份、城市、坐标、影集页面与照片数量组织成统一数据,再使用 MapLibre 显示去过的行政区和城市点位。即使地图加载失败,访客仍能通过下方影集入口浏览照片。 地图是相册的导航层,不是相册本身。照片仍由静态页面和灯箱承载,避免外部地图服务失败时整个相册不可用。 项目构建时从依赖复制 MapLibre 发布文件到: 不要长期依赖远程 JS/CDN。地图底图和行政区 GeoJSON 可以来自外部,但运行库本身应尽量由站点控制。 新建或编辑 source/_data/gallery.yml: admin_geojson 中的 {adcode} 会在浏览器端替换为省、市、区县行政代码。 字段说明: marker_offset 只在两个点位过近时使用,不要通过随意修改真实坐标来避免重叠。 父影集使用 children 指向城市影集,地图和影集导航都从这里读取关系。 source/gallery/index.md: 这个标签负责输出英雄区、地图容器、视图切换和根影集导航
转折
雨天总会让人有所思绪,平淡的日子里想起许久不曾更新的博客,拿出来记录一下这转折的半年。
蓝天碧海飞白鹭,波光远影泛渔舟——关于厦门的记忆
困在琐事许久,看海的心愈发难以压抑。聊城的考试结束后,来不及停留,火速乘坐动车前往与北方温差10°多的厦门。四天的鹭城旅途让人看够了海,并时时刻刻感受到来自厦门的浪漫。回校又疲于各种烦事,终于是有些许时间可以细细回忆,写下这篇旅途游记。 看海必来彩虹沙滩。即便是一夜动车,酒店放好东西后来不及休息,简单吃过午饭后直奔彩虹沙滩。这里不得不提一嘴厦门BRT,只有乘坐后才能理解那句话:“全国只有两种BRT,厦门BRT和其他BRT”。全程不堵车,平均速度大概40多,这才是真正意义上的快速公交。来到海边正是中午时刻,少有人影。这便是淡季旅行的优势——风景往往被自己一人承包。 随着海潮的涨起,我沿着海边,一路从彩虹沙滩看到乐海公园、嘉庚公园,许久以来心心念念、朝思暮想的大海,一下午算是看了个够。或许有时我喜爱的并不单纯是看海,更多的是享受这种吹拂海风、倾听海浪,给自己大脑一个完全沉溺于大自然而非烦于琐事的状态。上次这样沉溺已是一年以前——2024年9月底在滨海新区从妈祖园出来后夕阳下看海的时候。幻想过无数次在某个沿海城市定居,仿佛大海才会激起我对生活的向往,但往往唾手可得不会使人长久满足,只有保持适










