加载中...

加载中...

布局与页面

本页梳理 matery 主题的布局与页面相关功能:文章布局特性、侧边栏组件、响应式断点、相册、搜索、评论、暗色模式、加密、RSS/站点地图、PWA。每个功能给出配置位置与使用方法。

配置分两处:主题配置 themes/matery/_config.yml(布局/外观/交互)与站点配置 _config.yml(插件/生成器)。下面逐一标注。注意:本项目 CI 构建时主题配置文件会被 userConfig/_config.tmp.yml 模板覆盖,修改请同步模板(见「安装与主题配置」篇)。

怎么读这页:每个功能都按「效果 → 对应配置」成对展示——先看页面真实表现,再抄下面的 YAML/Stylus 配置。默认值取自 userConfig/_config.tmp.yml(与 themes/matery/_config.yml 同源),未在其中出现的取值集合标注「其他值未验证」。

布局核心与组件

1. 文章布局特性

用途:文章页外围的可选模块——上下篇、版权、时效提示、目录、广告位,决定「读完一篇之后往哪走」以及「这篇还能不能放心引用」。

学习路径:如何启用 → 常用选项(单篇覆盖)→ 全部可调项 → 边界与冲突

1.1 如何启用

上下篇导航

效果:文章末尾左右两张卡片,显示相邻文章标题与缩略图,hover 有渐变背景。

对应配置(主题配置,位于 post 块内):

post:
  prev_next:
    enable: true

版权声明

效果:文章底部灰色版权卡片,含作者、链接、许可协议三行。

对应配置(主题配置,位于 post 块内):

post:
  copyright:
    enable: true            # 显示版权声明
    license: 'cc_by_nc_sa'  # 默认转载规则(CC BY-NC-SA 4.0)

文章时效提示

效果:文章开头显示过期提示 note,天数越长样式越醒目(先警告色,再错误色)。

对应配置(主题配置,位于 post 块内;默认 enable: false):

post:
  outdate:
    enable: true      # 设为 true 开启
    warning_day: 365  # 超过 365 天显示警告样式 note
    error_day: 3650   # 超过 3650 天显示错误样式 note

TOC 目录

效果:桌面端侧边栏目录树随滚动高亮;移动端折叠收起。

对应配置(主题配置,顶层 toc 段):

toc:
  enable: true                        # 全局开关
  headingSelector: "h2,h3,h4,h5,h6"   # 参与目录的标题级别
  collapseDepth: 0                    # 折叠深度,0 全部折叠

广告位

效果:侧边栏 TOC 下方展示彩色广告卡片,支持明暗两套背景色。

对应配置(主题配置,位于 post 块内,数组可增删):

post:
  advertisements:
    - id: "ad-1"
      text: "自用超便宜的 VPS 服务商推荐"
      link: "https://example.com/your-aff-link"
      image: "/medias_webp/cover/hexo.webp"   # 可选:卡片图片
      background: "#6670ff"
      background_dark: "#3a4399"
      colspan: 1     # 卡片占列宽
      enable: true   # false 则隐藏

1.2 常用选项

效果:单篇文章不显示目录,其它文章不受影响。

对应配置(front-matter):

toc: false

效果:单篇文章改用自己的转载许可,站点默认值对它失效。

对应配置(front-matter):

reprintPolicy: cc_by_nc   # 本篇改为"署名-非商业性使用"

可用规则(共 9 种):cc_by、cc_by_nd、cc_by_sa、cc_by_nc、cc_by_nc_nd、cc_by_nc_sa、cc0、noreprint、pay。

效果:临时撤下某张或全部广告卡片,无需删配置。

对应配置:单条撤下把该条 enable 改 false;全站撤下把 advertisements 整段注释。

1.3 全部可调项

键类型默认可选值/范围作用
post.prev_next.enablebooltruetrue / false文末上下篇卡片
post.copyright.enablebooltruetrue / false文末版权卡片
post.copyright.licensestringcc_by_nc_sa上述 9 种之一默认转载规则
post.outdate.enableboolfalsetrue / false时效提示总开关
post.outdate.warning_dayint365天数超过即用警告样式
post.outdate.error_dayint3650天数超过即用错误样式
toc.enablebooltruetrue / false全局目录开关
toc.headingSelectorstring"h2,h3,h4,h5,h6"CSS 选择器参与目录的标题级别
toc.collapseDepthint00 = 全折叠;>0 = 有下级时展开目录折叠深度
post.advertisements[].id / text / linkstring——卡片标识、文案、跳转
post.advertisements[].imagestring—站内路径卡片配图(可选)
post.advertisements[].background / background_darkstring—颜色值明/暗两套底色
post.advertisements[].colspanint1列宽数卡片横向占比
post.advertisements[].enablebooltruetrue / false单条启停
page.tocbool继承全局true / false单篇目录覆盖
page.reprintPolicystring继承全局上述 9 种之一单篇许可覆盖

1.4 边界与冲突

  • 时效提示默认关闭:outdate.enable: false,不显式打开就不会出现提示,容易被误判为功能失效。
  • toc: false 是字符串比较:模板按 theme.toc.enable && page.toc !== 'false' 判断,写布尔以外的形式(如 "False")不生效。
  • 广告位与 TOC 共用同一块侧边栏区域:广告条数多、目录层级深时侧边栏明显变长;移动端侧边栏整体隐藏,两者都看不到。
  • 版权卡与「复制追加版权」不是同一功能:post.copyright 管文末卡片,post.copy.copyright 管复制正文时追加的文字,改错块不生效。

1.5 小结

  • 五个模块都是主题配置里的一行开关,除时效提示外默认全开。
  • 单篇粒度只有两个覆盖点:toc、reprintPolicy。
  • 改主题配置后必须 hexo clean && hexo generate;CI 场景还要同步 userConfig/_config.tmp.yml。

2. 页面级组件(widgets)

用途:分类/标签/归档/关于四个聚合页的可视化组件,全部由主题生成器自动渲染,随内容更新。

学习路径:如何启用(零配置)→ 全部可调项(无)→ 边界与冲突

2.1 如何启用

效果:下面这些页面在对应内容存在时自动出现图表 / 词云 / 时间线:

页面组件说明
/categories/分类雷达图canvas 雷达图展示各分类文章数量分布
/tags/标签云 + 词云chip 样式标签列表;canvas 词云字号 ∝ 文章数
/archives/归档时间线按年/月垂直时间线,圆点 + 年份折叠
/about/站点统计图表多组 canvas 图表(文章数/分类/标签/时间线等)
/about/站点统计数字文章数/分类数/标签数(_partial/post/post-statis,自动渲染)

对应配置:无(页面本身需在 source/ 下建页,layout 取 categories / tags / archives / about)。

2.2 常用选项

效果:图表配色随暗色模式切换,不需要单独设置。

对应配置:由 CSS 变量驱动(见 §7 暗色模式),未提供逐图表的配置项。

2.3 全部可调项

本组功能没有用户可调配置键——数据全部来自 Hexo 的 categories / tags / posts 模型,外观由 themes/matery/source/css/ 控制。

2.4 边界与冲突

  • 页面不存在时不会自动创建:/categories/ 等需要 source/categories/index.md 等文件存在。
  • 图表依赖 canvas 脚本;脚本被 CDN 拦截或懒加载失败时退化为空白区域,不报错。
  • 词云/雷达图的信息量来自文章数,文章很少(<5 篇)时图表几乎看不出差异。

2.5 小结

  • 零配置、零维护,代价是外观不可调。
  • 要改外观只能改 CSS/模板,不能靠配置。

3. 响应式断点

用途:定义手机 / 平板 / 桌面 / 大屏四档布局切换点,以及各档内容列的宽度上限。

学习路径:如何启用(变量)→ 常用选项(内容宽度)→ 全部可调项 → 边界与冲突

3.1 如何启用

效果:窗口缩放时,导航折叠、侧边栏收放、多栏切单栏按下列阈值发生。

对应配置(themes/matery/source/css/_variables/base.styl,Stylus 变量):

$breakpoint-sm  = 368px   // 超小屏(手机竖屏)
$breakpoint-md  = 768px   // 平板/手机横屏
$breakpoint-lg  = 992px   // 桌面
$breakpoint-xl  = 1200px  // 大屏
$breakpoint-fun = 1400px  // 特效启用阈值(大屏)

各断点布局表现:

断点布局表现
< 768px导航折叠为汉堡菜单,正文单列,侧边栏隐藏
768–992px平板布局,侧边栏收起
> 992px桌面多栏(正文 + 侧边栏 + TOC)
> 1400px特效启用(樱花/水波等)

布局基于 Materialize 栅格自适应,无需手动维护。

3.2 常用选项

内容宽度统一(2026-09-07)

效果:内容区在各档屏幕上都保持「正文可读、大屏不无限拉伸」——width: 90% 配上按屏幕分档的 max-width 上限。

对应配置(_variables/base.styl 的 $content-max-* / $content-wide-max-*):

断点标准(单栏)宽(多栏)
FHD 993-1920px1125px1250px
2K 1921-2560px1525px1750px
4K 2561px+1525px(封顶)2250px

选型规则(mixin content-container(wide)):

  • 单栏(无侧栏):content-container() → 标准
  • 多栏(有侧栏/TOC):content-container(true) → 宽
  • 禁止 layout 手写 max-width(统一走 mixin)

wiki(多栏)4K 内容列 899 → 1500px(+67%)。测试:tools/tests/content-width.test.js(L2m)。

3.3 全部可调项

变量类型默认可选值/范围作用
$breakpoint-smpx368px长度超小屏阈值
$breakpoint-mdpx768px长度手机横屏/平板阈值,导航折叠分界
$breakpoint-lgpx992px长度桌面多栏分界
$breakpoint-xlpx1200px长度大屏阈值
$breakpoint-funpx1400px长度特效启用阈值
$content-max-*px见上表长度单栏宽度上限
$content-wide-max-*px见上表长度多栏宽度上限

3.4 边界与冲突

  • 断点变量被大量 styl 文件引用,改动会同时影响导航、侧边栏、栅格、特效,「只改一处」的预期不成立。
  • 内容宽度必须走 content-container() mixin;layout 里手写 max-width 会与阶梯上限打架(大屏被截断或过宽)。
  • 这些是 Stylus 变量,不是 _config.yml 配置:改完需重新编译样式(hexo clean 后构建)。
  • $breakpoint-fun 只控制特效,不影响布局列数。

3.5 小结

  • 五个断点 + 两套宽度阶梯构成全部响应式行为。
  • 宽度优先级:单栏用标准、多栏用宽版,统一由 mixin 决定。

4. 相册功能

用途:用一份 YAML 维护全部相册(封面 + 描述 + 图片列表),自动生成列表页与灯箱内页。

学习路径:如何启用 → 常用选项(三种图片写法 / 加密封锁)→ 全部可调项 → 边界与冲突

4.1 如何启用

效果:/galleries/ 出现相册列表卡片(含封面与描述);点进内页是 lightGallery 灯箱,图片标题/描述显示为 caption。

对应配置(数据源 source/_data/galleries.yml,单点维护):

2020:
  cover: /medias_webp/images/01.webp
  description: 2020 年跨年
  photos:
    - url: /medias_webp/images/01.webp      # 形式一:完整对象(url/title/desc)
      title: "2020跨年"
    - /medias_webp/images/02.webp           # 形式二:仅路径
    - dir: /medias_webp/featureimages/      # 形式三:目录,自动扫描全部图片
      title_prefix: "图"

对应配置(新建相册页):

hexo new gallery <名称>

生成 source/galleries/<名称>/index.md(front-matter 只需 title + layout: gallery)。

4.2 常用选项

效果:进入相册先要求输密码,输对后才渲染图片。

对应配置(相册页 front-matter 加 password):

---
title: 2020 跨年
layout: gallery
password: "********"
---

效果:一个目录下的图片全部收录,不必逐张写路径。

对应配置:photos 里用 dir: 形式(见 §4.1 第三种写法),可配 title_prefix 自动生成标题前缀。

4.3 全部可调项

键类型默认可选值/范围作用
<相册名>map—任意键名相册标识(也是页内标题来源)
coverstring—站内图片路径列表页封面
descriptionstring—文本列表页描述
photosarray—对象 / 字符串 / dir 对象图片列表,三种形式可混用
photos[].url / title / descstring——单图地址与标题、描述
photos[].dirstring—目录路径扫描该目录全部图片
photos[].title_prefixstring—文本自动编号标题前缀
page.passwordstring—任意字符串相册加密

4.4 边界与冲突

  • 改 galleries.yml 必须清缓存:数据变更会撞上 Hexo 增量缓存误判(site.data 变 undefined、页面空白)。容器内用 tools/cicd.sh -d,本地用 rm -f db.json && hexo generate。
  • 相册名同时是 URL 段:改名等于换地址,旧链接 404。
  • dir 形式会扫描目录下全部图片,目录里混入封面/临时图会一起进相册。
  • 加密只保护内页;列表页的封面与描述仍公开。

4.5 小结

  • 一份 galleries.yml 管所有相册,图片支持单图/路径/目录三种写法。
  • 加密码是相册级(整本),不是单张图级。

5. 搜索功能

用途:导航栏搜索弹窗,三套引擎(local / Algolia / Pagefind)可独立启停,前端按需切换。

学习路径:如何启用 → 常用选项(引擎对比 / 快捷键 / 多语言过滤 / Pagefind 构建)→ 全部可调项 → 边界与冲突

5.1 如何启用

效果:导航栏出现搜索框;点击弹出搜索面板,输入关键词实时出结果,/search.json 作为本地索数据源,加密文章自动从索引排除。

对应配置(主题配置的 search 块,三引擎):

search:
  algolia:
    enable: true        # Algolia 引擎(applicationID/apiKey/indexName 见主题配置)
    indexName: "blog"
  local:
    enable: true        # 本地搜索:hexo generate 时由生成器输出 /search.json
    path: /search.json
    field: [post, wiki] # 搜索范围:post | page | wiki | all,可用数组组合
    content: true       # 是否索引正文
  pagefind:
    enable: true        # Pagefind 静态索引(构建后浏览器端搜索)
    output_subdir: pagefind

5.2 常用选项

三引擎配置键与默认引擎

效果:不同引擎各有取舍——local 无外部服务、Algolia 体验最好但依赖外部索引、Pagefind 纯静态且索引在构建期生成。

对应配置:原键名以 themes/matery/_config.yml 的 search 块为准(模板 userConfig/_config.tmp.yml 同源):

引擎配置块关键键说明
local 本地search.local.*enable / path / field / content / format: striptags / preload / trigger / top_n_per_article构建时由主题生成器输出 search.json;preload/trigger 当前未接入实现,实际始终在首次打开搜索弹窗时下载索引
Algoliasearch.algolia.*enable / applicationID / apiKey / indexName / content_length / excerpt_length / batch_size / hits.per_page / labelsapiKey 是前端检索 Key(可暴露);写库 Key 单独放在 deploy.algolia_write_key(仅构建时读取)
Pagefindsearch.pagefind.*enable / output_subdir: pagefind构建时扫描 public/ 生成静态索引,浏览器端搜索,无外部服务

效果:站点默认用哪个引擎由一行决定;配错了不会白屏,而是降级。

对应配置(顶层 search.default):

search:
  default: "algolia"   # algolia | local | pagefind
  • search.default(值 algolia / local / pagefind)指定默认引擎;若配置的默认引擎未启用,前端自动降级为第一个已启用引擎并 console.warn。
  • Algolia 客户端(algoliasearch)按需加载:打开搜索弹窗时才注入,不再全站预加载。

页内切换引擎与快捷键

(源:themes/matery/layout/_partial/common/search.ejs、_partial/script/search.ejs)

效果:弹窗内可即时换引擎、换完自动重搜,下次打开还记得上次选择;Ctrl+K 随时唤起。

对应配置:无(内置行为),要点如下:

  • 弹窗左侧引擎图标 #searchEngineBtn 展开下拉菜单 #searchEngineMenu,在 local / algolia / pagefind 间切换;可用引擎 ≤ 1 时下拉按钮自动隐藏。
  • 结果按当前引擎实时渲染,切换引擎时会用输入框当前值立即重搜;当前引擎记忆在 localStorage(键 search_engine)。
  • 快捷键 Ctrl+K / Cmd+K 打开搜索弹窗,Esc 关闭菜单;弹窗用原生 popover,点击外部自动 light dismiss。
  • 中文输入法兼容:输入事件跳过 IME composition 中间态,compositionend 兜底用完整值搜索(三引擎共用)。

多语言过滤与统一高亮

(源:themes/matery/source/js/search.js)

效果:同一篇文档的多语言版本不会重复刷屏,只留用户偏好语言那一条;关键词在结果与跳转页都被安全高亮。

对应配置:无(内置行为),要点如下:

  • 多语言过滤:三引擎共用 applyLangFilter()——按路径语言前缀分组,优先返回用户偏好语言(localStorage 键 wiki_lang,语言列表来自 window.MATERY_LANG.langs)命中的那条,缺失则回落默认语言(default_lang),同组去重。
  • 统一高亮:三引擎共用基类 _highlight()——关键词先转义再生成成对 <mark class="search-keyword">(防 XSS / 标签不闭合);Algolia 返回的高亮 HTML 经 _safeHighlight() 剥离后重新高亮。
  • 跳转页高亮:结果链接附 ?highlight=<关键词>,文章页由 search.ejs 尾部脚本解析并高亮正文(跳过代码块与链接)。

Pagefind 构建步骤

效果:public/pagefind/ 生成静态索引,浏览器端无外部服务即可搜索。

对应配置(在 hexo generate 之后、部署之前扫描 public/,运行于 CI 阶段,见 tools/CI.sh):

npx --no-install pagefind --site public --output-subdir pagefind \
  || npx --yes pagefind@1.5.2 --site public --output-subdir pagefind

优先用本地已装版本,未装则用固定版本 pagefind@1.5.2 一次性下载(避免 npx 拉最新版漂移)。

5.3 全部可调项

键类型默认可选值/范围作用
search.defaultstringalgoliaalgolia / local / pagefind默认引擎,未启用则降级
search.algolia.enablebooltruetrue / falseAlgolia 引擎开关
search.algolia.applicationIDstring—Algolia 应用 ID索引归属
search.algolia.apiKeystring—前端检索 Key只读检索(可暴露)
search.algolia.indexNamestringblog索引名搜哪个索引
search.algolia.content_lengthint—字符数推送到 Algolia 的正文截断长度
search.algolia.excerpt_lengthint—字符数结果摘要长度
search.algolia.batch_sizeint—条数单次推送批量
search.algolia.hits.per_pageint—条数每页结果数
search.algolia.labelsmap—文本结果区文案
search.local.enablebooltruetrue / false本地搜索开关
search.local.pathstring/search.json路径索引输出位置
search.local.fieldarray[post, wiki]post / page / wiki / all搜索范围
search.local.contentbooltruetrue / false是否索引正文(false 仅标题)
search.local.formatstringstriptagsstriptags / raw索引正文格式
search.local.triggerstringautoauto / manual触发方式(当前未接入实现)
search.local.top_n_per_articleint1-1 = 全部每篇最多命中片段数
search.local.preloadbool—true / false预加载(当前未接入实现)
search.pagefind.enablebooltruetrue / falsePagefind 引擎开关
search.pagefind.output_subdirstringpagefind目录名(勿用下划线开头)索引输出子目录

5.4 边界与冲突

  • preload / trigger 是配置了但没实现的键:设了也不改变行为,索引始终在首次打开弹窗时下载。
  • Algolia 单条记录硬上限 10KB:正文太长会被服务端拒绝(HTTP 400),需靠 content_length 截断;中文按 3 字节/字符算,上限比英文低得多。
  • output_subdir 不能用下划线开头:GitHub Pages(Jekyll)会忽略 _ 开头的目录,索引直接不发布。
  • Pagefind 必须在 hexo generate 之后跑:顺序颠倒时扫到的是旧产物或空目录。
  • 三引擎同时开启会让配置互相掩盖问题:排查搜索异常时先只留一个引擎验证。

5.5 小结

  • 三引擎互相独立,search.default 决定首选,未启用自动降级。
  • local 与 Pagefind 都是纯静态方案,Algolia 需要额外推送索引。
  • field / content / content_length 是控制索引体积的三个主要旋钮。

6. 评论系统

用途:文章、留言页、友链页共用的 Waline 评论,支持 Markdown/Emoji/点赞/后台管理。

学习路径:如何启用 → 常用选项(单页开关)→ 全部可调项 → 边界与冲突

6.1 如何启用

效果:文章底部出现评论框,自动跟随明暗模式;未登录也可发表(按服务端配置)。

对应配置(主题配置):

waline:
  enable: true
  serverURL: 'https://waline.17lai.site'  # 你的 Waline 服务端
  lang: zh-CN
  dark: 'html[data-user-color-scheme="dark"]'  # 跟随暗色模式
  login: enable
  wordLimit: 1000
  pageSize: 10

6.2 常用选项

效果:某篇文章(或某个页面)不显示评论区,其它页面照常。

对应配置(front-matter):

comments: false    # true 显示 / false 隐藏

6.3 全部可调项

键类型默认可选值/范围作用
waline.enablebooltruetrue / false评论区总开关
waline.serverURLstring—服务端 URL评论数据归属
waline.langstringzh-CN语言码界面语言
waline.darkstringhtml[data-user-color-scheme="dark"]CSS 选择器暗色模式下套用的样式
waline.loginstringenableenable / 其他值未验证是否要求登录
waline.wordLimitint1000字符数单条评论字数上限
waline.pageSizeint10条数每页评论数
waline.avatarstringmp''/mp/identicon/monsterid/wavatar/retro/hide头像来源
page.commentsbool继承全局true / false单页开关

6.4 边界与冲突

  • 客户端与服务端版本必须一致:Waline 版本错配会导致评论框加载出来但提交失败。
  • serverURL 写错不会报错:只是评论框空白或一直 loading,需看浏览器网络面板确认。
  • 暗色模式靠 dark 选择器:若主题的 data-user-color-scheme 属性被改,评论框会一直亮色。
  • waline 与 valine 两套配置同时存在,启用哪个看 enable;同时开会出现两个评论框。

6.5 小结

  • 启用只需 enable + serverURL 两行,其余是体验微调。
  • 单页粒度用 front-matter comments。

7. 暗色模式

用途:由 [data-user-color-scheme] 属性驱动的整套 CSS 变量切换,覆盖正文、图片、图表、评论。

学习路径:如何启用 → 常用选项(三种默认模式)→ 全部可调项 → 边界与冲突

7.1 如何启用

效果:页面出现明暗切换按钮;默认按系统偏好或本地时间自动切,用户手动切换后记住选择。

对应配置(主题配置):

dark_mode:
  enable: true
  default: auto   # auto | light | dark

7.2 常用选项

效果:三种默认策略的表现差异如下。

对应配置:上面的 dark_mode.default。

  • auto:优先遵循 prefers-color-scheme,其次按本地时间 18:00–6:00 自动进入暗色
  • light / dark:固定初始模式,用户手动切换后覆盖
  • 手动切换按钮会覆盖默认模式(记忆用户选择)

7.3 全部可调项

键类型默认可选值/范围作用
dark_mode.enablebooltruetrue / false是否提供切换与暗色样式
dark_mode.defaultstringautoauto / light / dark初始模式
image.light_filter / light_filter_darkstringbrightness(1) / brightness(0.92)CSS filter亮/暗下图片滤镜
image.card_opacity / card_opacity_darkstring0.85 / 0.70–1亮/暗下卡片透明度

7.4 边界与冲突

  • 暗色值不走 _config.yml 单一来源:颜色在 color-schema.styl 的 [data-user-color-scheme="dark"] 块里成对定义,只改一处会亮暗不匹配。
  • auto 的时段判断用访客本地时间,不是站点时区;同一时刻不同地区用户看到的模式可能不同。
  • 第三方组件(评论、ECharts)各自有暗色适配逻辑,新增组件时要单独接 data-user-color-scheme。
  • 手动切换的选择存在浏览器本地,清理站点数据会回到默认模式。

7.5 小结

  • 一个属性(data-user-color-scheme)+ 一套 CSS 变量 = 全站暗色。
  • 新增任何自绘组件都要同时写亮/暗两份变量,否则暗色下会出现「白斑」。

8. 加密

用途:文章 / 相册 / 内容片段 / 整个 wiki 四种粒度的密码保护,前端 WebCrypto 解密。

学习路径:如何启用 → 常用选项(四种方式 / wiki 整体加密 / 页内 front-matter)→ 全部可调项 → 边界与冲突

8.1 如何启用

效果:被加密的文章页显示解密 UI(#hbePass),输入正确密码后渲染正文;密码错误显示提示文案。

对应配置(自研 HBE v4 体系,2026-08-09 起去插件化,替代 hexo-blog-encrypt;AES-256-GCM + PBKDF2 250k 轮,文章/相册/片段/wiki 统一。前端 WebCrypto 解密,hexo-blog-decrypt 事件触发主题刷新。主题 encrypt 段):

encrypt:
  enable: true
  abstract: 有东西被加密了, 请输入密码查看.
  message: 您好, 这里需要密码.
  tags:                     # 按标签加密:命中标签的文章自动加密
    - {name: 私人, password: "********"}
  wrong_pass_message: 抱歉, 这个密码看着不太对, 请再试试.
  autoSave: true            # 派生 key 缓存到 localStorage(1 天 TTL),刷新免输密码

8.2 常用选项

四种加密方式

效果:从「整篇按标签批量加密」到「只藏一段」,共四种粒度。

对应配置:

方式用法说明
标签加密文章打 encrypt.tags 中标签命中标签自动整篇加密
单篇加密front-matter password: "********"整篇加密
内容片段加密encrypt tag(密码 + 标题 + 简介)段落级加密,支持内部 tag 嵌套(2026-09-07 方案 Y)
Wiki 整体加密{wiki}-sidebar.yml 加 encrypt_password整个 wiki 一密码,跨页共享 dk(2026-09-07)

片段加密的完整写法(参数:密码、标题、简介):

{% encrypt 密码 "标题" "简介" %}markdown 内容{% endencrypt %}

Wiki 整体加密

效果:加密中间内容 + 右侧 TOC,左侧导航保留(相当于可见标题);解密任一页,该 wiki 所有语言页共享解锁状态(1 天 TTL)。

对应配置(任一 {wiki}-sidebar.yml,如 source/_data/dev-sidebar.yml;统一 encrypt_ 前缀):

encrypt_password: "整个wiki的密码"       # 必填
encrypt_message: "该文档受密码保护"       # 可选:提示语
encrypt_wpm: "密码错误"                  # 可选:错误提示
encrypt_placeholder: "请输入密码"        # 可选:输入占位
encrypt_button_text: "解锁"             # 可选:按钮文字

Wiki 页 front-matter 清单(2026-09-03)

效果:wiki 页面能按需打开 Mermaid、MathJax、锚点、Prism 插件、ECharts,或关掉目录/评论/加密本页。

对应配置:wiki 页面(layout: wiki)支持的 front-matter 与文章一致,常用项:

front-matter效果
mermaid: true启用 Mermaid 流程图/时序图
mathjax: true启用 MathJax 公式
toc: false关闭本页目录
comment: false关闭本页评论
anchorjs: false关闭标题锚点
treeview: true启用 Prism treeview 代码树插件
autolinker: true启用 Prism autolinker 链接插件
diffhighlight: true启用 Prism diff 高亮插件
echarts: true启用 ECharts 图表(需正文含图表容器)
password: "********"加密本页(解锁体验与文章一致)

ECharts 图表(2026-09-03 统一)

效果:正文里出现可交互图表,明暗模式自动适配,3D/globe 等 GL 图表也能用。

对应配置(front-matter 加 echarts: true,加载 libs echarts(latest,当前默认 v6.1.0)+ echarts-gl 2.1.0):

{% echarts 宽 高 %}
{ "xAxis": { "type": "category", "data": ["A","B"] }, "yAxis": { "type": "value" }, "series": [{ "type": "bar", "data": [1,2] }] }
{% endecharts %}
  • 文章内图表:echarts 标签(参数依次为宽、高,宽默认 100%、高默认 400px)+ option JSON
  • 明暗:自动适配(init 传当前主题,切换时重建)
  • GL 图表:option 含 grid3D/globe 等 GL 组件时自动可用(echarts-gl 已加载)
  • 注意:echarts 6 要求 xAxis 显式声明 type(category/value)

8.3 全部可调项

键类型默认可选值/范围作用
encrypt.enablebooltruetrue / false加密体系总开关
encrypt.abstractstring见上文本未解锁时的摘要
encrypt.messagestring见上文本解锁框提示
encrypt.tagsarray—{name, password} 列表按标签批量加密
encrypt.wrong_pass_messagestring见上文本密码错误提示
encrypt.autoSavebooltruetrue / false派生 key 缓存(1 天 TTL)
page.passwordstring—任意字符串单篇/单页加密
<wiki>-sidebar.yml: encrypt_passwordstring—任意字符串wiki 整体密码(必填即启用)
encrypt_message / encrypt_wpm / encrypt_placeholder / encrypt_button_textstring—文本wiki 解锁框文案
page.echartsboolfalsetrue / false加载 ECharts 运行时

8.4 边界与冲突

  • enable: false 会让已加密内容变不可读:加密产物仍在,但前端不再加载解密逻辑,表现为空白或原样输出密文——重新开启才恢复。
  • autoSave 是便利也是风险:解密 key 缓存在 localStorage(1 天),共用设备上等于一天内免密。
  • wiki 密码与文章密码互相独立:改了 wiki 的 encrypt_password,已经解锁过的浏览器仍可凭旧 key 读到旧页(TTL 内)。
  • hexo-blog-encrypt 插件已弃用:只认本主题的 encrypt 段,按旧插件文档配置无效。
  • 片段加密里的 raw 标签少写一个就会在构建期报 unknown block tag(本页示例已加)。
  • 资源压缩(2026-09-25):hbe 加密资源已统一进 source/libs/hbe/ 并走静态管线,hexo-minify 对其生效(此前绕过压缩管线)。

8.5 小结

  • 四种粒度:标签批量、单篇、片段、整个 wiki。
  • 全是前端解密,防的是「随手翻到」,不是服务端权限控制——密文与密钥派生参数都在页面里。
  • wiki 解锁状态跨页共享,1 天 TTL。

发布与独立页面

9. RSS / 站点地图

用途:输出三类订阅源与两套站点地图,供阅读器与搜索引擎抓取。

学习路径:如何启用 → 常用选项(条数 / 输出名)→ 全部可调项 → 边界与冲突

9.1 如何启用

效果:站点根目录生成 /rss.xml、/atom.xml、/feed.json 三个订阅源,以及 /sitemap.xml、/baidusitemap.xml 两份站点地图。

对应配置(根 _config.yml,hexo-feed + hexo-generator-sitemap):

feed:             # 三类订阅源独立开关
  rss:
    enable: true
    output: "rss.xml"
  atom:
    enable: true
    output: "atom.xml"
  jsonFeed:
    enable: true
    output: "feed.json"
  limit: 10

sitemap:          # 通用站点地图
  path: sitemap.xml

baidusitemap:     # 百度站点地图
  path: baidusitemap.xml

9.2 常用选项

效果:订阅源只保留最近 20 篇,减小单文件体积。

对应配置:

feed:
  limit: 20

效果:换掉订阅源输出文件名(如统一到 /feed/rss.xml)。

对应配置:改 feed.rss.output / feed.atom.output / feed.jsonFeed.output(RSS 模板为 themes/matery/layout/_partial/rss.ejs)。

9.3 全部可调项

键类型默认可选值/范围作用
feed.rss.enablebooltruetrue / false输出 RSS 2.0
feed.rss.outputstringrss.xml文件名RSS 输出路径
feed.atom.enablebooltruetrue / false输出 Atom
feed.atom.outputstringatom.xml文件名Atom 输出路径
feed.jsonFeed.enablebooltruetrue / false输出 JSON Feed
feed.jsonFeed.outputstringfeed.json文件名JSON Feed 输出路径
feed.limitint10篇数订阅源条目上限
sitemap.pathstringsitemap.xml路径通用站点地图
baidusitemap.pathstringbaidusitemap.xml路径百度站点地图

9.4 边界与冲突

  • 这三项在根 _config.yml,不是主题配置;写进主题配置不生效。
  • 生成器在构建期输出,改配置后不 hexo clean 时旧文件仍留在 public/。
  • 加密文章仍会出现在订阅源里(标题/摘要),只是正文加密;要彻底排除需在生成器层过滤。
  • 换了 output 路径,旧的订阅地址立刻 404,老读者会断更。

9.5 小结

  • 三类订阅源各自独立开关,limit 控制条数。
  • 两份站点地图分别给通用搜索引擎与百度。

10. PWA

用途:把站点变成可安装、可离线访问的 PWA;每次构建自动换缓存版本并让客户端静默刷新一次。

学习路径:如何启用 → 常用选项(SW 版本管理)→ 全部可调项 → 边界与冲突

10.1 如何启用

效果:浏览器地址栏出现安装入口(manifest + 主题色生效);断网时已缓存页面仍可打开;站点更新后自动刷新一次到新版。

对应配置(主题配置):

pwa:
  enable: true

userConfig/sw.tmp.js 是 Service Worker 模板:CI 时注入离线缓存版本号(17lai-cache-{时间戳})生成 source/sw.js。

10.2 常用选项

SW 版本管理细节

(源:userConfig/sw.tmp.js、themes/matery/layout/_partial/common/head.ejs、tools/cicd.sh)

效果:部署新版后用户无需手动刷新、也不会被弹窗打断;旧版本缓存自动清理。

对应配置:无(由 CI 与模板协作),要点如下:

  • 模板 → 产物:CI 构建时 tools/cicd.sh 的 inject_pwa_sw() 先把 userConfig/sw.tmp.js 复制为 source/sw.js,再用 sed 注入占位符;产物发布为站点根路径的 /sw.js。
  • 缓存键 / 版本注入:模板用字面量 17lai-cache-{uniqueIdentifier} 作为缓存键,缓存名前缀为 17lai-cache-;CI 用构建时间戳(date '+%Y%m%d%H%M%S',即 offline_version)替换占位符,得到形如 17lai-cache-20260913181700 的唯一键——每次构建即新版本。同一步还会注入 {cdnUrl} / {cdnPathVersion} / {cdnPathLatest} / {urlVersion} 等占位符。
  • 客户端自动刷新一次(head.ejs,theme.pwa.enable 时以 async 脚本注册,scope: '/';localhost 下跳过注册,避免本地开发命中旧缓存):
    1. 注册后经 MessageChannel 向 SW 发 checkIdentifier 消息,取回当前缓存版本号并记录基准。
    2. updatefound → 新 SW installed(预缓存 addAll 完成),以及 controllerchange(SW 接管)两个时机触发 checkVersionAndRefresh()。
    3. 仅当缓存版本号变化才自动 window.location.reload()(延迟 500ms 等 activate 完成);refreshed 守卫保证每页只刷一次,避免 Vercel 重复部署触发循环刷新——无弹窗、无手动刷新。
  • 激活与旧缓存清理(SW 模板):install 事件预缓存 cacheList 后 self.skipWaiting();activate 事件遍历 caches.keys(),删除前缀为 17lai-cache- 且不等于当前缓存键的旧缓存,重新 addAll 后 self.clients.claim() 接管所有页面。
  • 压缩版备份:release 模式把未压缩 sw.js 备份到 userConfig/sw.js,构建完成再备份压缩版到 userConfig/sw.min.js;continue 模式复用 sw.min.js 以保证压缩产物一致(缺失则回退模板版)。

10.3 全部可调项

键 / 文件类型默认可选值/范围作用
pwa.enablebooltruetrue / false注册 SW 与 manifest
userConfig/sw.tmp.js模板——SW 源码(CI 注入版本号后输出 source/sw.js)
{uniqueIdentifier}占位符构建时间戳YYYYMMDDHHMMSS缓存键,每次构建变化
{cdnUrl} / {cdnPathVersion} / {cdnPathLatest} / {urlVersion}占位符CI 注入—SW 内资源地址
userConfig/sw.min.js文件——continue 模式复用的压缩产物

10.4 边界与冲突

  • SW 缓存最容易造成「改了不生效」:本地 localhost 已跳过注册,但用域名访问测试域时会命中旧缓存——排查前先注销 SW / 清站点数据。
  • 版本号不变不会触发更新:只改内容不重新构建(或 -c 复用旧版本)时缓存键不变,客户端可能继续用旧缓存。
  • 模板占位符没被注入(本地直接 hexo generate)时,{cdnUrl} 等会以字面量留在 sw.js 里,导致缓存请求 404。
  • localhost 跳过注册是刻意行为,别在本地调试「为什么没有 SW」。

10.5 小结

  • PWA 开关只有一个,真正复杂的是 sw.tmp.js 的版本注入链路。
  • 缓存键 = 构建时间戳,因此「每次部署都是新版本」。

11. 独立页面(Standalone Pages)

用途:主题提供的专用 layout 页面(影视/短片/留言/友链/联系/404),页面正文写在 md 里,结构由模板渲染。

学习路径:如何启用(逐个 layout)→ 常用选项(数据源 / front-matter)→ 全部可调项 → 边界与冲突

11.1 如何启用

以下页面由主题提供专用 layout 模板,需在 source/ 下创建对应页面(front-matter 指定 layout),页面正文写在 md 文件中,模板负责渲染。

av 影视页(layout: av)

⚠️ 已废弃(2026-09-12):av layout 无实际用途,已从主题删除(themes/matery/layout/av.ejs 移除、source/av/ 不再创建)。以下内容仅作历史参考——请勿再按此创建该页。

效果(历史设计):影视/资源分享页,结构类似关于页——音乐播放器 + 视频 + 我的相册 + 资源分享正文。

对应配置(历史数据源,已无模板消费):

  • theme.music(音乐播放器,见「交互视觉」篇 §9)
  • theme.video(视频播放器,见「交互视觉」篇 §10)
  • theme.myGallery(我的相册,见「侧边栏组件」篇 §8)
  • page.content(页面正文,资源分享列表)

当时的建页方式(当前项目未建此页):

hexo new page av

source/av/index.md front-matter:

---
title: 影视资源
layout: av
---

movies 电影页(layout: movies)

效果:励志短片页,页面中是一个 Bilibili iframe 播放器(地址硬编码在模板里)。

对应配置(项目已有 source/movies/index.md):

---
title: 视频
layout: movies
---

数据源:无数据文件——短片地址硬编码在 themes/matery/layout/movies.ejs 的 iframe src 中,更换短片需编辑模板。

msg 留言页(layout: msg)

效果:留言板——正文(博客时间线等)+ 留言信封组件 + 评论区;信封有展开动画与留言表单提示(样式 letter.styl,文案 i18n letter.*)。

对应配置(项目已有 source/msg/index.md):

---
title: 留言板
layout: msg
toc: false          # 关闭 TOC(模板按 theme.toc.enable && page.toc !== 'false' 判断)
comment: waline
---

评论开关:模板经 inject_point('pageComments') 注入评论,front-matter comment: waline(或 comments: true)开启。

friends 友链页(layout: friends)

效果:友链卡片墙(Masonry 瀑布流),卡片背景色按顺序循环 frind-card1~frind-card10;页面正文显示在友链列表下方,评论区经 linksComments 注入点渲染。

对应配置(项目已有 source/friends/index.md):

---
title: 'For My Friends!'
layout: friends
comment: waline
---

数据源(source/_data/friends.yml,纯数组,模板经 site.data.friends 读取):

- name: 友链名称            # 必填,卡片标题
  url: https://example.com  # 必填,跳转地址
  avatar: /favicon.png      # 必填,头像
  introduction: 一句话介绍  # 必填
  title: 前去学习           # 可选,按钮文字

contact 联系页(layout: contact —— ⚠️ 活动主题未实现,勿用)

注意:活动主题 themes/matery/layout/ 中不存在 contact.ejs(仅未启用的上游参考主题有),layout: contact 不会渲染。以下内容仅供了解历史设计。

效果(设计意图):联系页——页面正文 + 弹幕互动(文字/链接/速度)+ 评论区。

对应配置(历史设计):基于 LeanCloud(AV)存储的 barrager 弹幕,valine/waline 任一启用(theme.valine.enable 或 theme.waline.enable)即显示弹幕表单;客服组件(daovoice / tidio / tuxiaochao)见「交互视觉」篇 §14。

当时的建页方式(当前项目未建此页):

hexo new page contact

source/contact/index.md front-matter:

---
title: 联系我
layout: contact
---

404 页(layout: 404)

效果:未找到页面提示 + 搜索入口 + 倒计时 8 秒跳转首页;banner 图按日期每日切换(/medias_webp/banner/{0-6}.webp)。

对应配置(项目已有 source/404.md):

---
title: 404
layout: 404
excerpt: "Oops~,我崩溃了!找不到你想要的页面 :("   # 显示在页面描述处
---

11.2 常用选项

效果:控制某个独立页面是否出目录、是否出评论。

对应配置(页面 front-matter):

toc: false          # 关闭本页目录
comment: waline     # 挂载 Waline 评论(或用 comments: true)

效果:友链卡片按列表顺序换配色,无需写样式。

对应配置:friends.yml 的条目顺序即配色顺序(循环 frind-card1~frind-card10)。

11.3 全部可调项

layout 值页面模板状态
av/av/已删除(av.ejs 移除)已废弃(2026-09-12)
movies/movies/themes/matery/layout/movies.ejs可用(视频地址硬编码)
msg/msg/themes/matery/layout/msg.ejs可用
friends/friends/themes/matery/layout/friends.ejs可用(数据源 friends.yml)
contact/contact/不存在未实现,勿用
404/404.htmlthemes/matery/layout/404.ejs可用
page.toc各独立页—true / false,关目录
page.comment / page.comments各独立页—开启评论
page.excerpt404 等—页面描述文案

11.4 边界与冲突

  • layout: av 和 layout: contact 都是死配置:写了不报错,只是回落到默认 page 模板(或空白),排查时很容易误判成样式问题。
  • movies 内容不可配:视频地址在 .ejs 里,改短片必须改主题代码(属代码改动,发布要走 -r)。
  • 友链的 frind-card* 拼写是错字但已固化:按正确拼写 friend-card 改样式不会命中。
  • 独立页面要同时在 source/ 建页:只写配置不建 md 文件,路由不存在。
  • 页面级 toc / comment 只对支持注入点的 layout 有效。

11.5 小结

  • 当前可用四个半:movies、msg、friends、404(av 已删、contact 未实现)。
  • 数据源固定的只有 friends(source/_data/friends.yml),其余靠模板硬编码或注入点。
  • 建页三件套:hexo new page <名> + front-matter layout + (必要时)数据文件。

附:布局功能速查表

功能位置配置位置说明
上下篇导航文章底部主题 post.prev_next按时间取相邻文章
版权声明文章底部主题 post.copyright(含 license 子键)front-matter reprintPolicy 单篇覆盖
时效提示文章开头主题 post.outdate默认关闭,按天数分级
TOC 目录文章侧边栏主题 tocfront-matter toc: false 单篇关闭
广告位侧边栏主题 post.advertisements数组多卡片,可单独启停
分类雷达图/categories/自动渲染无需配置
标签云/词云/tags/自动渲染无需配置
归档时间线/archives/自动渲染无需配置
关于页图表/about/自动渲染无需配置
响应式断点全局base.styl 的 $breakpoint-* 变量368/768/992/1200/1400
相册/galleries/source/_data/galleries.ymlhexo new gallery 建页
搜索导航栏主题 search(algolia/local/pagefind)三引擎可独立启停
评论文章/留言等页主题 walinefront-matter comments 控制开关
暗色模式全局主题 dark_modeauto 跟随系统 + 时段
加密文章页根 encrypt标签加密或 front-matter password
RSS/Sitemap根路径根 feed / sitemap / baidusitemap三类订阅源 + 双站点地图
PWA全局主题 pwa + userConfig/sw.tmp.js离线缓存 + 可安装
独立页面/movies/ /msg/ /friends/ /404source/ 下建页 + front-matter layout四种专用模板,见 §11(/av/ 已删除、/contact/ 模板未实现)
评论
数据加载中 ...