上一篇:使用 Inject 添加自定义组件 · 系列总目录 · 下一篇:从定制走向独立主题

前言

完成基础配置后,本站没有直接修改 Butterfly 的主题包,而是持续通过 source/csssource/js 和 Hexo 生成脚本增加功能。

这些组件有些只是普通的前端代码,可以移植到任何网站;有些会读取 Hexo 生成的数据;还有一些专门依赖 Butterfly 的 DOM 和 PJAX。了解这种差异,可以避免把“使用了 Hexo”和“只能在 Hexo 中运行”混为一谈。


一、组件与框架的关系

可以把组件分成三类:

类型 特征 迁移难度
通用前端组件 只需要 HTML、CSS、JavaScript
Hexo 数据组件 读取文章、分类或生成阶段数据
Butterfly 增强组件 依赖 Butterfly DOM、主题切换或 PJAX 中到高

例如音乐播放器本身不要求 Hexo;分类磁贴的动画也不要求 Hexo,但当前脚本读取 Butterfly 分类页生成的类名,因此迁移时需要替换数据入口。


二、全局音乐播放器

本站音乐播放器位于页面左下角,主要功能包括:

  • 网易云歌单加载
  • 播放与暂停
  • 上一首和下一首
  • 音量调节
  • 顺序、随机、列表循环和单曲循环
  • 侧边收起与悬浮展开
  • 预先检查下一首是否可播放
  • PJAX 页面跳转后保持全局可用

它的主体是原生 JavaScript 和 CSS,并不是只有 Hexo 才能使用。迁移到其他网站时需要:

  1. 在全局布局中加载播放器资源。
  2. 提供歌单数据接口。
  3. 把 PJAX 生命周期替换为目标框架的路由生命周期。

需要注意,用户拥有网易云 VIP 并不代表访客可以通过第三方网页播放器获得完整 VIP 权限。VIP、版权限制、地区限制和接口状态都由音乐服务决定。

完整实现已经在独立教程中介绍:

为博客部署自制网易云音乐播放器


三、分类全息磁贴

Butterfly 默认分类总览主要是文字链接。本站在不修改主题模板的情况下,把它增强为:

  • 双列响应式磁贴
  • 分类名称和文章数量
  • 独立图标、说明和色相
  • 指针跟随高光
  • 轻微 3D 倾斜
  • 暗色主题适配
  • 奇数卡片居中
  • 手机端单列

实现方式是读取:

1
.category-lists .category-list-item

然后保留原始链接,重新组织内部结构。JavaScript 失败时仍会显示 Butterfly 默认分类列表,这是一种渐进增强。

完整教程:

为 Hexo 分类页添加全息磁贴


四、标签星座

标签页适合表达内容之间的联系,而不只是标签名称列表。本站将标签展示成具有空间层次的星座节点:

  • 标签数量映射为视觉权重
  • 明暗主题分别配色
  • 悬浮显示强调效果
  • 手机端降低动态并保持可点击区域

它当前读取 Butterfly 标签页 DOM,因此属于 Butterfly 增强组件。若迁移到独立主题,可以直接在模板阶段输出同样的数据结构,省去浏览器中的二次重组。


五、技术参考与朋友友链

友链页面被拆分为:

1
2
3
4
5
技术参考
Hexo / Butterfly / 设计参考

我的朋友
朋友博客和个人介绍

技术参考采用一行三张的紧凑卡片,悬浮时放大并展示更多信息;朋友区域使用更完整的头像与介绍卡。

这个设计解决了两类链接语义不同的问题:

  • 技术资料强调访问效率。
  • 朋友链接强调人物与关系。

实现仍是普通 HTML、CSS 和 JavaScript,可迁移性较高。


六、全局命令面板搜索

原生搜索入口适合传统博客,但内容和组件增加后,需要一个更接近桌面应用的全局入口。

本站命令面板提供:

  • 固定在右上角的入口
  • 键盘快捷键
  • 搜索文章标题、简介和标签
  • 快速打开分类、标签、日志和友链
  • 支持 PJAX 导航
  • 手机端独立排版

它的数据来自 Hexo 生成的搜索索引,因此搜索界面是通用组件,数据层则属于 Hexo 集成。

有了全局检索后,原来的搜索按钮可以隐藏,避免两个入口功能重复。


七、首页单列与双列切换

访客可以选择:

  • 一行一篇:更适合阅读摘要
  • 一行两篇:更适合快速浏览

组件需要处理:

  • 奇数篇文章的最后一张卡片
  • 不同卡片高度
  • 手机端强制单列
  • 用户选择的本地保存
  • 页面切换后的布局恢复

用户偏好可以保存到:

1
localStorage.setItem('post-layout', 'grid');

这个功能与 Butterfly 首页 DOM 有一定耦合,但核心网格逻辑可以迁移。


八、随机封面图池与固定映射

这是一个 Hexo 生成阶段组件,而不是浏览器组件。

工作流程:

1
2
3
4
5
6
7
8
9
读取 source/img/post-covers

找到没有显式 cover 的文章

从使用次数较少的图片中随机选择

保存到 data/cover-assignments.json

后续部署继续使用同一张

只有图片被移出图池时,对应文章才会重新分配。这样既保留随机性,又避免每次部署后封面变化。

文章页首图和首页封面被分离处理,防止竖图在标题横幅中被严重裁切。

这个功能依赖 Hexo 的生成钩子,迁移到其他静态生成器时需要改写构建插件,但算法本身可以保留。


九、页脚运行状态与旅行者一号

页脚目前组合了:

  • 博客运行时间
  • 旅行者一号任务信息
  • 简短状态文字
  • “暗淡蓝点”格言

状态规则被简化为:

1
2
部署后的 3 小时内:忙碌中,正在建设
其他时间:博客在线,安静运行

部署脚本写入最后部署时间,浏览器脚本计算当前状态。这比根据随机事件或访问动作推测站长状态更加明确。

旅行者一号数据会定期更新,不应该把一个永远不变的距离数字直接写死在页面中。


十、自动更新日志

本站部署流程不仅执行 hexo deploy,还在 npm 脚本中加入:

  • 更新外部数据
  • 检查项目变化
  • 收集待发布日志
  • 标记部署时间
  • 生成网站
  • 执行部署

更新日志不会每次自动发布为文章,而是先积累在本地记录中。等变化足够多时,再统一整理到日志页面。

这说明:

1
npm run deploy

和:

1
hexo deploy

可能具有不同效果。前者执行 package.json 中定义的完整流程,后者只调用 Hexo 部署器。


十一、文章简介悬浮详情

首页卡片为了整齐通常会限制摘要行数,但长简介会被截断。本站在摘要确实溢出时提供悬浮详情:

  • 普通状态保持固定高度
  • 鼠标悬浮显示完整文本
  • 没有溢出时不创建提示
  • 手机端不依赖 hover

这类功能要先比较元素的 scrollHeightclientHeight,不能给所有摘要无条件显示重复提示。


十二、时钟组件为什么被停用

页首时钟曾显示日期、时间和状态,但它过于显眼,会与首页标题和背景争夺视觉中心。因此组件代码被保留,默认注入被注释。

这是组件设计中很重要的一点:

功能完整不等于应该启用。

博客首先是阅读空间。一个组件如果无法改善导航、阅读或氛围,就应该降低存在感,甚至暂时关闭。

时钟的完整制作方式仍保留在教程中:

为博客添加时光状态组件


十三、如何决定下一个组件

可以用四个问题筛选:

  1. 它解决了真实问题吗?
  2. 原生配置是否已经能够完成?
  3. 手机端和无障碍状态怎样处理?
  4. 主题升级后维护成本有多高?

优先开发:

  • 改善导航和搜索的组件
  • 减少重复操作的自动化
  • 强化文章组织方式的组件
  • 与网站内容气质一致的轻量氛围效果

谨慎添加:

  • 大面积跟随鼠标动画
  • 自动播放音频
  • 多个功能重复的悬浮按钮
  • 阻挡正文的弹窗
  • 依赖不稳定第三方接口的核心功能

下一篇将讨论这些定制内容怎样逐步脱离 Butterfly,形成结构清晰的独立 Hexo 主题。


参考资料与声明

本文中的组件均来自本站实际使用或保留的实现。部分结构与文字由 AI 协助整理。


上一篇:使用 Inject 添加自定义组件 · 返回系列总目录 · 下一篇:从定制走向独立主题