我为 Hexo 博客开发了一款原生微信小程序


扫码预览效果
一直以来,我都在使用 Hexo 维护自己的技术博客。Hexo 很适合组织和发布长期内容,但在手机上阅读时,网页与原生应用之间仍然存在一些体验差距:每次都要打开浏览器、寻找网址,页面加载和导航也很难做到像小程序一样轻便。

于是,我为自己的博客开发了一款原生微信小程序——NNU 技术博客小程序

它不是简单地在小程序里套一层网页,而是直接读取 Hexo 生成的文章索引,在小程序端完成解析、分类、搜索和正文渲染。博客仍然负责内容生产,小程序则成为一个更适合移动阅读的新入口。

项目已经开源:

为什么要做这个小程序

我希望它解决三个问题。

让已有博客内容自然进入微信

重新为小程序维护一套文章数据库,会让内容发布变得非常繁琐。文章在 Hexo 中更新后,还要再上传一次小程序后台,这不仅重复劳动,也容易造成两个平台内容不一致。

因此,这个小程序不维护独立的文章数据库,而是直接读取 Hexo 输出的 search.xml。只要博客完成发布,小程序下一次刷新时就能获取新内容。

提供真正适合移动端的阅读界面

小程序采用原生 WXML、WXSS 和 JavaScript 开发,没有通过 web-view 直接嵌入整个博客。首页、分类、搜索、文章详情、收藏和阅读历史都拥有独立的小程序页面。

这样可以获得更自然的页面切换、触觉反馈、下拉刷新、图片预览、代码复制和微信分享体验。

尽量保持简单的部署架构

项目不需要单独部署内容 API,也不需要额外的数据库。文章、分类和标签来自 Hexo;收藏、搜索记录和阅读历史保存在微信本地存储;评论及浏览数据则复用博客已有的 Twikoo 接口。

整个数据链路可以概括为:

1
2
3
4
5
6
7
8
9
Markdown 文章

Hexo 构建并发布博客

生成 search.xml 和文章页面

微信小程序请求并解析数据

首页 / 分类 / 搜索 / 文章详情

项目定位

这不是一个通用 CMS,也不是一个带后台管理系统的小程序。它更像是 Hexo 博客的移动阅读客户端。

内容仍然通过熟悉的 Hexo 工作流维护:

1
2
3
hexo new post "文章标题"
hexo generate
hexo deploy

小程序只负责读取和展示已经发布的内容,因此不会改变原有博客的写作方式,也不会把文章锁定在微信生态中。

核心功能

首页内容聚合

首页是整个小程序的信息入口,包含文章推荐、分类快捷入口、精选内容和最新文章列表。

小程序启动后会请求:

1
https://www.nnu.cn/search.xml

随后解析文章的标题、链接、正文、摘要、日期、作者、分类、标签和封面图,并把结果写入全局数据。页面支持下拉刷新,博客更新后不需要重新发布小程序即可读取最新文章。

首页还会抓取博客归档页和首页数据,用于补齐更准确的发布日期、文章封面和展示信息。

即刻短文

除了正式文章,首页还读取博客的“即刻短文”页面。短内容可以包含文字、图片和音频,小程序会将其整理成适合移动浏览的信息流。

音频内容使用微信原生音频能力播放,并展示播放状态、进度和时长;图片可以直接调用微信预览界面。

即刻短文同样接入评论功能,让博客上的轻量动态和小程序保持一致。

分类与标签

小程序会从 XML 索引中提取文章分类和标签,不需要在代码里手动录入完整列表。

分类页根据文章数量动态生成卡片,并通过关键词匹配图标。例如网络、服务器、Docker、NAS、Windows、校园和生活等分类都会尽可能匹配对应视觉符号。

没有预设图标的分类也不会显示成完全相同的样式:项目会根据分类名称计算稳定的颜色与图标组合,使新增分类仍然能够自然融入界面。

点击分类或标签后进入独立文章列表。列表按每批 8 篇逐步加载,降低一次渲染大量节点带来的性能压力。

全文搜索

搜索功能完全在小程序本地完成,不需要调用搜索服务。

用户输入关键词后,小程序会在已经解析的文章数据中匹配:

  • 文章标题;
  • 正文内容;
  • 内容摘要;
  • 分类;
  • 标签。

最近使用的搜索词会保存在本机,最多保留 10 条。页面也提供 Docker、NAS、运维、部署和教程等快捷关键词。

由于搜索基于已下载的 XML 索引,它没有远程搜索接口的额外延迟,也不会把用户的搜索记录发送到服务器。

原生文章详情页

文章详情是这个项目投入较多的一部分。Hexo 输出的是面向浏览器的 HTML,而微信小程序的 rich-text 对标签、事件和样式存在不少限制,因此不能直接原样显示。

当前实现会对正文进行一次专门的转换:

  • 解码常见 HTML 实体;
  • 处理 Hexo 高亮代码块;
  • 为标题、段落、引用和行内代码补充移动端样式;
  • 让表格支持横向滚动;
  • 将图片转换为可点击预览的原生节点;
  • 将链接转换为可点击复制的内容块;
  • 拆分代码块,支持一键复制和展开长代码;
  • 根据文章主题色调整引用、链接和代码样式。

详情页还提供阅读进度、返回顶部、字数统计、预计阅读时间和相关文章推荐。

相关文章不是随机抽取,而是根据共同分类和标签计算分数:同分类权重更高,同标签作为补充,最终展示关联度最高的文章。

评论与浏览数据

小程序复用了博客已有的 Twikoo 服务。目前评论请求通过:

1
https://capi.nnu.cn/

详情页支持:

  • 获取文章浏览量;
  • 获取评论列表和回复;
  • 发布评论;
  • 点赞评论;
  • 显示评论头像;
  • 使用表情包;
  • 保存常用昵称和邮箱。

用户的昵称和邮箱只保存在本机,后续评论时自动填入。头像使用 Cravatar 服务生成,评论表情则通过独立表情接口获取。

如果评论服务暂时不可用,文章正文仍然可以正常阅读,评论区域会独立显示失败状态,不会阻塞整个详情页。

收藏与阅读历史

收藏和历史记录都使用微信小程序本地存储实现,不要求用户登录。

收藏记录会保存文章 ID、标题、封面、日期、分类和摘要。再次点击收藏按钮即可取消收藏。

每次打开文章时,小程序会把它加入阅读历史,并自动移除重复记录。历史最多保留 50 条,最近阅读的文章排在最前面。

这套设计足够简单,也避免了为个人博客额外维护用户系统。不过,它的边界也很明确:更换手机、清理小程序数据或删除小程序后,本地收藏和历史不会自动恢复。

季节主题与视觉皮肤

小程序目前提供多套浅色主题:

  • 自动匹配季节;
  • 春日薄荷;
  • 盛夏晴空;
  • 秋日奶杏;
  • 冬日雾蓝;
  • 清透蓝绿;
  • 经典蓝白。

自动模式会根据当前季节选择皮肤。每套皮肤都定义了背景、卡片、输入框、正文、品牌色、边框、阴影和导航栏等变量,而不是只简单替换一个主题色。

页面使用半透明卡片、柔和背景光和自定义底部导航,整体设计目标是清爽、轻盈,并尽量把注意力留给内容。

个人中心

“我的”页面用于汇总站点和本地数据,包括:

  • 文章总数;
  • 分类总数;
  • 可验证时显示的总浏览量;
  • 全站评论数量;
  • 博客运行时间;
  • 本地收藏数量;
  • 本地阅读历史数量;
  • 当前使用的主题皮肤。

页面还提供收藏、历史、关于和主题设置入口。

技术实现

原生微信小程序

项目使用微信原生框架开发,主要文件由以下几类组成:

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
nnuwx/
├── app.js # 全局状态、收藏、历史和统计
├── app.json # 页面、窗口和 TabBar 配置
├── app.wxss # 全局样式
├── custom-tab-bar/ # 自定义底部导航
├── components/
│ ├── nav-bar/ # 自定义导航栏
│ └── float-tabbar/ # 浮动导航组件
├── pages/
│ ├── index/ # 首页和即刻短文
│ ├── categories/ # 分类与标签
│ ├── list/ # 分类文章列表
│ ├── search/ # 本地搜索
│ ├── detail/ # 文章详情与评论
│ ├── favorites/ # 收藏
│ ├── history/ # 阅读历史
│ ├── profile/ # 个人中心
│ ├── about/ # 关于页面
│ └── webview/ # 白名单网页内容
├── utils/
│ ├── parser.js # XML、文章及评论数据解析
│ ├── theme.js # 主题状态管理
│ ├── theme-config.js # 皮肤变量
│ ├── category-color.js # 分类配色
│ ├── icon-color.js # 动态 SVG 图标着色
│ └── vibrate.js # 触觉反馈
└── images/ # 图标与本地资源

项目没有 package.json,也没有依赖第三方小程序组件库。下载源码后可以直接使用微信开发者工具导入。

XML 数据解析

Hexo 搜索插件生成的 XML 可能是 RSS,也可能接近 Atom 格式,不同主题和插件生成的字段也不完全一致。

项目中的解析器同时兼容 <entry><item>,并对以下字段进行归一化:

1
2
3
4
5
6
7
8
title       → 标题
link/url → 原文地址
content → 正文
summary → 摘要
published → 发布时间
category → 分类
tag → 标签
author → 作者

如果文章没有设置封面,小程序会从正文中提取第一张图片;仍然找不到时,再使用预设的兜底图片。

为了防止每次启动都得到变化的展示数据,当前实现只汇总真实可验证的浏览量。旧版本可能产生的随机统计缓存会被忽略。

本地状态管理

项目没有引入状态管理框架,而是使用 App.globalData 保存当前会话的数据:

1
2
3
4
5
6
7
8
9
10
globalData: {
blogUrl: 'https://www.nnu.cn/search.xml',
articles: [],
categories: [],
tags: [],
favorites: [],
history: [],
theme: 'auto',
themeSkin: 'summer'
}

需要持久化的部分通过 wx.setStorageSync() 写入本地。对于个人博客小程序,这种结构足够直观,也降低了维护成本。

如何运行项目

1. 下载源码

1
git clone https://github.com/anyfrees/nnuwx.git

2. 使用微信开发者工具导入

打开微信开发者工具,选择“导入项目”,将项目目录指向刚刚下载的 nnuwx 文件夹。

仓库中的 project.config.json 已将项目类型设置为原生小程序。如果只是本地体验,可以使用测试 AppID;准备正式发布时,应改成自己的小程序 AppID。

3. 修改博客地址

当前源码中的博客域名为:

1
https://www.nnu.cn

二次使用时,至少需要全局搜索并替换以下地址:

1
2
3
4
5
https://www.nnu.cn/search.xml
https://www.nnu.cn/
https://www.nnu.cn/archives/
https://www.nnu.cn/essay/
https://www.nnu.cn/atom.xml

同时修改 app.js 中的:

1
blogUrl: 'https://你的域名/search.xml'

如果博客没有“即刻短文”、Twikoo 或赞赏页面,可以隐藏对应入口,或者替换为自己的服务。

4. 确保 Hexo 生成搜索索引

小程序依赖包含正文的 search.xml。Hexo 博客需要安装并配置相应搜索索引插件,例如 hexo-generator-search

示例配置思路如下,具体字段请根据所使用的插件版本调整:

1
2
3
4
search:
path: search.xml
field: post
content: true

生成博客后,直接在浏览器打开下面的地址进行确认:

1
https://你的域名/search.xml

如果 XML 中只有标题而没有正文,小程序仍然可以显示文章列表,但搜索范围和详情内容会不完整。

5. 配置服务器域名

开发配置中关闭了 URL 校验,方便在开发者工具里调试;正式发布时,这并不能代替微信公众平台的服务器域名配置。

需要根据实际功能,在“小程序后台 → 开发管理 → 开发设置 → 服务器域名”中添加合法域名,可能包括:

  • 自己的 Hexo 博客域名;
  • Twikoo API 域名;
  • 评论头像域名;
  • 表情资源域名;
  • 文章及封面图片所在域名。

所有请求地址应使用 HTTPS。若文章引用了多个外部图床,还需要逐一确认微信小程序能否合法加载,或者统一迁移到自己的图床/CDN。

6. 修改站点信息

二次使用时,还应修改:

  • app.json 中的小程序标题;
  • 关于页面中的博客名称、介绍和作者;
  • GitHub、RSS 和博客链接;
  • 站点图标与 TabBar 图标;
  • 博客创建时间;
  • 赞赏二维码及公众号文章地址;
  • 分享标题和默认分享图。

修改完成后,在真机上重点测试文章详情、图片预览、代码复制、评论、分享和不同网络环境下的请求表现。

当前版本的边界

这个项目最初是围绕 NNU 技术博客开发的,因此目前仍然存在一些站点耦合:

  • 博客、归档和即刻短文地址写在源码中;
  • Twikoo 接口使用 NNU 的服务地址;
  • 部分快捷入口和分享文案是固定内容;
  • 赞赏二维码和公众号页面属于站点专属配置;
  • 外部图片依赖对应域名能够在小程序中访问;
  • 收藏、历史和搜索记录不会跨设备同步;
  • 没有独立登录、后台管理和消息推送系统。

因此,它目前更准确的定位是“可供参考和二次开发的个人博客小程序”,而不是下载后填写一个域名就能适配所有 Hexo 主题的通用模板。

后续可以改进的方向

如果继续完善,我计划优先考虑以下方向:

集中配置

把博客域名、XML 地址、评论接口、站点信息、赞赏信息和快捷入口集中到一个配置文件,减少全局搜索替换。

增加缓存策略

为文章索引增加缓存时间、版本检测和离线兜底,在网络不稳定时优先展示上一次成功获取的内容。

改进富文本兼容性

继续完善复杂表格、嵌套列表、数学公式、流程图和更多 Hexo 标签插件的渲染能力。

提供可选云同步

在保持免登录模式的同时,可以增加可选的微信云开发同步,让用户在多设备间恢复收藏和阅读历史。

形成真正的通用模板

提供清晰的配置文件、初始化脚本、部署检查清单和示例 Hexo 配置,让其他博客作者能更快接入。

开源说明

源码托管在 GitHub:

1
https://github.com/anyfrees/nnuwx

欢迎根据自己的 Hexo 博客进行二次开发。如果发现文章解析、真机样式、域名兼容或评论接口方面的问题,也可以通过 GitHub Issue 提交反馈。

需要特别说明的是,仓库当前没有独立的许可证文件。在作者补充开源许可证之前,公开可见并不自动等于允许任意复制、修改和再发布;如需将它用于其他公开或商业项目,请先联系确认授权。

写在最后

这个小程序的核心价值,不是把博客网页原封不动地搬进微信,而是在保留 Hexo 内容工作流的基础上,为文章重新设计一套移动阅读体验。

博客依然是内容的源头,小程序只是新的窗口。文章发布一次,就能同时服务网站和微信用户;收藏、搜索、阅读历史、主题和评论则让这个窗口更接近一款完整的阅读应用。

对于我来说,它也是一次把长期维护的个人博客继续向前延伸的尝试:不追求复杂的后台和庞大的架构,而是围绕自己的真实使用习惯,把阅读这件事做得更轻、更顺手。