加载中...

加载中...

本文既是 matery 主题交互视觉功能的完整使用教程,也是 自动化测试靶场。覆盖:代码块增强、图片灯箱、打字机、页面特效、繁简转换、进度条、回顶、打赏、打印。

阅读方式:每个功能都先看 效果(真实渲染或行为描述),再看 对应配置(产出该效果的最小片段),需要查参数时直接跳到「全部可调项」的表。


── 代码与打印 ──

1. 代码块增强

用途:代码块自动带语言标签,并提供复制 / 展开 / 折叠 / 全屏操作,超长代码限高。

学习路径:开语言标签 → 配复制与展开按钮 → 调限高 → 全参数表 → 边界与冲突

1.1 如何启用

效果(本节下面的代码块就是真实渲染结果:右上角语言标签 + 复制按钮,超长块底部出现"展开"条):

# Bash:系统操作
sudo apt update
docker compose up -d
systemctl status nginx
# Python:数据处理
def process(data):
    """处理数据并返回结果"""
    result = [x * 2 for x in data if x > 0]
    return result

print(process([1, -2, 3, 4]))
// JavaScript:异步请求
async function fetchData(url) {
  const response = await fetch(url);
  const data = await response.json();
  console.log("数据:", data);
}
# YAML:配置文件
server:
  host: 0.0.0.0
  port: 8080
  workers: 4

对应配置(最小可用:语言标签 + 复制按钮,其余全关):

code:
  language:
    enable: true
    default: "TEXT"
  copy_btn: true

标准 Markdown 代码块即可,不需要额外语法 —— 上面四块就是普通的三反引号 + 语言名写法。

1.2 常用选项

① 限高与展开(最常用的一个组合)

效果:下面这段超长 Python 超过 450px 高度阈值,默认折叠,底部出现"展开"条,点开后完整显示(不再限高):

# Python:超长代码示例(超过 450px 高度阈值,触发"展开"按钮)
# 模拟一个简单的博客文章处理流水线
import hashlib
import json
import re
from collections import Counter
from datetime import datetime
from pathlib import Path


def read_posts(directory):
    """读取目录下所有 Markdown 文章"""
    posts = []
    for path in Path(directory).glob("*.md"):
        posts.append(path.read_text(encoding="utf-8"))
    return posts


def extract_front_matter(content):
    """提取 Front-Matter 元数据"""
    match = re.match(r"^---\n(.*?)\n---\n", content, re.DOTALL)
    if not match:
        return {}
    meta = {}
    for line in match.group(1).splitlines():
        if ":" in line:
            key, value = line.split(":", 1)
            meta[key.strip()] = value.strip()
    return meta


def analyze_posts(directory):
    """主分析流程:统计词频、生成摘要、计算字数"""
    all_words = Counter()
    for content in read_posts(directory):
        meta = extract_front_matter(content)
        body = re.sub(r"^---\n.*?\n---\n", "", content, flags=re.DOTALL)
        text = re.sub(r"[#*`>\[\]()]", "", body)
        words = re.findall(r"[\u4e00-\u9fa5]|[a-zA-Z]+", text)
        all_words.update(words)
        word_count = len(words)
        summary = " ".join(words[:20])
        checksum = hashlib.md5(content.encode()).hexdigest()[:8]
        print(f"{meta.get('title', 'untitled')} | {word_count}字 | {checksum}")
        print(f"  摘要: {summary}...")
    print(f"\n共分析 {len(all_words)} 个词汇")
    return all_words


if __name__ == "__main__":
    result = analyze_posts("content/posts")
    top_words = result.most_common(10)
    print("Top 10 高频词:")
    for word, count in top_words:
        print(f"  {word}: {count}")

对应配置:

code:
  height_limit: "450px"   # 超过该高度自动折叠
  show_full: true         # 折叠态底部给"展开"按钮
  shrink: true            # 给"主动折叠"按钮

② 语言标签兜底文案

效果:未识别的语言(或未写语言)代码块,标签位置显示的是 default 指定的文案;默认值是 TEXT。

对应配置:

code:
  language:
    enable: true
    default: "TEXT"    # 换成 "CODE" 则标签显示 CODE

③ 复制按钮

效果:右上角出现复制按钮,点击复制整块代码。

对应配置:

code:
  copy_btn: true       # false = 右上角只剩语言标签

④ 全屏按钮

效果:代码块工具栏出现全屏按钮,点击后该代码块铺满视口(这也是 §17 的「代码全屏」)。

对应配置:

code:
  show_expand: true

全屏按钮是否出现还取决于资源加载 —— 本节未逐一验证各组合,其他值未验证。

⑤ 超宽行换行 / 横向滚动

效果:break: false 时超宽行不换行,改为横向滚动(本文按此值使用)。

对应配置:

code:
  break: false

⑥ 展开的内部机制(为什么点开就不限高了)

效果:点"展开"后容器 maxHeight 被设为 scrollHeight(完整高度,内部无滚动条,滚动交给页面);点"收起"恢复 maxHeight 为空,重新回到 --code-max-height 的 450px。

对应机制(code-area 组件,非配置项):

  • 限高:code.height_limit(默认 "450px")落到 CSS 变量 --code-max-height
  • 展开:折叠态底部显示 scroll-down-bar 展开条,点击后 JS 将容器 maxHeight 设为 scrollHeight
  • 横向滚动:代码容器 overflow-x: auto
  • 全屏:code.show_expand: true 提供全屏查看

测试断言:页面含 code-area 标记(≥4 个代码块);readmode 用例(L11)验证展开后代码完整显示。

1.3 全部可调项

键类型默认可选值/范围作用
code.language.enablebooltruetrue / false右上角语言标签开关
code.language.defaultstring"TEXT"任意字符串语言无法识别时显示的标签文案
code.copy_btnbooltruetrue / false复制按钮
code.show_fullbooltruetrue / false超长代码的展开/折叠按钮
code.shrinkbooltruetrue / false主动折叠按钮
code.height_limitstring"450px"带单位的 CSS 长度(px 等)超过该高度自动折叠
code.breakbool—false(本文件按此值使用)超宽行是否换行;false 时改为横向滚动
code.show_expandbool—true / false代码块全屏查看按钮

1.4 边界与冲突

  • height_limit 落到 CSS 变量 --code-max-height;展开时 JS 把 maxHeight 直接设为 scrollHeight(不再受该值限制),收起时恢复。
  • copy_btn / show_full / shrink 是三个独立按钮,可任意组合;全关则只剩裸代码块。
  • 语言标签只在 language.enable: true 时输出;未识别语言回落 language.default。
  • 改本段任一项都必须 clean 构建才生效(见「已知坑」坑 5)。

代码块委托幂等(codeWidget)

加密 wiki 页的代码块按钮(折叠/复制)点击无效。根因:codeWidget() 在「页面加载 + 解密后刷新」被调用多次,document 上的 click 委托累积,classList.toggle 执行偶数次后净效果为零。修复:命名 handler(_codeWidgetClickHandler)先 removeEventListener 再 add;Prism 兜底回调加 _codeWidgetPrismRegistered 幂等标记。

测试断言:readmode-integration.test.js「codeWidget 二次调用后单次点击仍生效」。

Wiki 页行号(prism line-numbers)

Wiki 文档页(layout/wiki.ejs)代码块走 prism 渲染并启用 line-numbers 行号,与文章页代码块增强(toolbar)并存。

测试断言:TC-L15 G5(tools/tests/wiki-prism-integration.test.js,4 断言):tutorial 页加载 / prism-core / 代码块 / line-numbers 行号。

1.5 小结

  • 最小可用:language.enable + copy_btn 两行就够
  • 怕长文爆炸:调 height_limit,show_full 负责给"展开"条
  • 想少一行代码:break: true 换行,不要横向滚动
  • 改完不生效:几乎都是缓存 —— clean 构建(坑 5)

── UI 交互与动效 ──

2. 图片灯箱 lightGallery

用途:文章图片点击放大浏览,支持缩放/翻页/下载。

学习路径:开灯箱 → 普通图片即可 → 尺寸注入前置 → 全参数 → 边界与冲突

2.1 如何启用

效果(真实渲染:hover 有阴影 + 边框,点击弹出全屏灯箱,可缩放、翻页,alt 作文案显示):

灯箱测试图1

灯箱测试图2

对应配置:

# 文章图片自动被 articleInit 包装为 .img-item
image_zoom:
  enable: true

2.2 常用选项

① 普通 Markdown 图片就够

效果:正文 <img> 被 articleInit() 包装成 .img-item,点击弹出 .lg-outer 灯箱(就是上面两张图的行为)。

对应配置(Markdown 源码,无需额外属性):

![图片描述](/medias_webp/featureimages/1.webp)

② 网络图尺寸映射

效果:命中映射表的 CDN 图直接读本地文件取真实尺寸(省一次网络请求),未命中的异步拉取 —— 灯箱打开时图片不会跳一下(防 CLS)。

对应配置:

image_size_plugin:
  map_paths:
    <CDN 路径>: <本地文件路径>

map_paths 的完整结构未在本文件展开,其他值未验证。

③ 灯箱库来源

效果:决定灯箱能力的实现库;换成不可达地址时灯箱整体失效。

对应配置:

libs:
  js:
    lightgallery: <CDN 地址或本地路径>

libs.js.lightgallery 的完整取值形态未在本文件展开,其他值未验证。

2.3 全部可调项

键类型默认可选值/范围作用
image_zoom.enablebooltruetrue / false灯箱总开关
libs.js.lightgallerystring—库地址(公共 CDN 或本地路径)lightGallery 库来源
image_size_plugin.map_pathsmap—CDN 路径 → 本地文件路径网络图映射到本地读尺寸

libs.js.lightgallery 的完整取值形态未在本文件展开,其他值未验证。

2.4 边界与冲突

  • 灯箱依赖 imgsize.js 先注入 width/height:脚本顺序固定,跳过尺寸注入时打开灯箱会触发重排(CLS)。
  • 只作用于正文图片(articleInit() 包装为 .img-item),Banner/封面/卡片缩略图不在范围内。
  • 尺寸缓存 image_sizes_cache.json 30 天 TTL、上限 5000 条;超限后旧条目淘汰,对应图片会重新拉取尺寸。

图片尺寸注入前置(imgsize.js)

灯箱打开前,主题脚本 scripts/events/lib/imgsize.js 会为页面所有 <img> 注入真实 width/height(防 CLS):

  • 本地图片:同步读取文件尺寸,直接注入
  • 网络图片:命中缓存直接用;命中 CDN→本地映射(image_size_plugin.map_paths)读本地文件;其余异步拉取
  • 缓存持久化:image_sizes_cache.json(30 天 TTL,上限 5000 条)
  • 正则兼容:匹配 src 三种形态(带引号/单引号/无引号),兼容 hexo-minify 去引号

该脚本在灯箱绑定之前执行,确保 articleInit() 包装 img → .img-item 时已有尺寸属性,灯箱打开不触发重排。

测试断言:图片被包装为 .img-item,点击弹出 .lg-outer。

2.5 小结

  • 开箱即用:image_zoom.enable: true,图片写普通 Markdown 即可
  • 只覆盖正文图:封面/缩略图不会进灯箱
  • 首屏跳动:查 imgsize.js 是否先于灯箱执行,而非改灯箱参数

3. 打字机 Typed

用途:Banner 副标题 / 文章标题逐字打字动画。

学习路径:开副标题打字 → 循环与光标 → 调速 → 全参数 → 边界与冲突

3.1 如何启用

效果:首页 Banner 副标题逐字打出,打完停一下再删除、重新打下一句;页面含 #typed 与 .typed-cursor 标记。

对应配置:

subtitle:
  enable: true
  typed:
    enable: true

subtitle.enable 是宿主开关 —— 关掉它,副标题整体不显示,打字机自然无宿主。

3.2 常用选项

① 循环轮播

效果:loop: true 打完一轮继续删掉重打;loop: false 只打一遍(结束后光标是否保留等其他组合未验证)。

对应配置:

subtitle:
  typed:
    loop: true

② 光标外观

效果:showCursor: true 时末尾有闪烁光标(.typed-cursor),字符由 cursorChar 决定 —— 本文件使用下划线 _。

对应配置:

subtitle:
  typed:
    showCursor: true
    cursorChar: "_"

③ 速度与启动延迟

效果:typeSpeed 越小打字越快,backSpeed 越小删除越快(50 < 80 即删除比打字快),startDelay 是开打前的停顿。

对应配置:

subtitle:
  typed:
    startDelay: 100   # 启动延迟(ms)
    typeSpeed: 80     # 打字速度(ms/字)
    backSpeed: 50     # 删除速度(ms/字)

④ 文章页标题打字机

效果:文章页标题也逐字打出(与 Banner 副标题是两套独立开关)。

对应配置:

post:
  typed:
    enable: true

3.3 全部可调项

键类型默认可选值/范围作用
subtitle.enablebooltruetrue / falseBanner 副标题是否显示(打字机的宿主)
subtitle.typed.enablebooltruetrue / falseBanner 副标题打字机开关
subtitle.typed.loopbooltruetrue / false是否循环轮播
subtitle.typed.showCursorbooltruetrue / false是否显示光标
subtitle.typed.cursorCharstring"_"任意单字符光标字符
subtitle.typed.startDelaynumber100毫秒启动前延迟
subtitle.typed.typeSpeednumber80毫秒/字打字速度(越小越快)
subtitle.typed.backSpeednumber50毫秒/字删除速度(50 < 80 即删除比打字快)
post.typed.enablebooltruetrue / false文章页标题打字机开关

3.4 边界与冲突

  • subtitle.typed.* 挂在副标题上:subtitle.enable: false 时副标题整体不显示,打字机自然无宿主。
  • loop: false 只打一遍(结束后光标是否保留等其他组合未验证)。
  • typeSpeed / backSpeed / startDelay 单位都是毫秒,写字符串(如 "80ms")不在片段验证范围内。
  • 改本段后必须 clean 构建(见「已知坑」坑 5)。

3.5 小结

  • 只想开打字机:subtitle.enable + subtitle.typed.enable 两行
  • 嫌慢:调小 typeSpeed / backSpeed
  • 文章标题不动:那是 post.typed.enable,与 Banner 无关

测试断言:页面含 #typed 或 .typed-cursor 标记。


4. 页面特效

用途:装饰特效 —— 页面/背景特效(樱花/水波/落叶/雪花/网络/彩带等)与鼠标/点击特效(爱心/星星/烟花等),两组各自互斥单选。

学习路径:开总开关 → 选一个页面特效 → 选一个鼠标特效 → 桌面门控 → 全参数 → 冲突

4.1 如何启用

效果:页面上出现所选装饰动画(如樱花持续飘落),鼠标移动/点击时出现所选点击特效;移动端默认不加载。

对应配置(只开页面特效,鼠标特效保持关闭):

effects:
  enable: true
  page:
    default: sakura        # 樱花
  mouse:
    default: off

4.2 常用选项

① 页面/背景特效(单选)

效果:default 指定的那一个才生效 —— 写 sakura 见樱花,写 ripples 见水波,写 off 什么都不加。

对应配置:

effects:
  page:
    default: off        # off | random | 具体 id
    available:
      sakura:        { label: 樱花, lib: sakura }
      ripples:       { label: 水波, lib: ripples }
      leaf:          { label: 落叶, lib: leaf }
      snowdown:      { label: 飘雪, lib: snowdown }
      snowflake:     { label: 雪花, lib: snowflake }
      buble:         { label: 冒泡, lib: buble }
      canvas_nest:   { label: 网络, lib: canvas_nest }
      ribbon:        { label: 彩带, lib: ribbon }
      ribbon_dynamic: { label: 动态彩带, lib: ribbon_dynamic }

② 鼠标/点击特效(单选)

效果:点击或移动鼠标时出现对应反馈 —— clicklove 爱心、mouseStar 星星、fireworks 爆炸、popupText 弹出文字。

对应配置:

effects:
  mouse:
    default: off
    available:
      clicklove:     { label: 爱心, lib: clicklove }
      popupText:     { label: 弹出文字, lib: popupText }
      mouseStar:     { label: 星星, lib: star }
      fireworks:     { label: 爆炸, lib: fireworks }

③ 只在桌面端注入

效果:desktop_only: true 时移动端完全不加载特效脚本(省电省流量);设 false 则移动端也加载。

对应配置:

effects:
  desktop_only: true

④ 运行时切换(不改代码)

效果:打开右下角悬浮面板即可切换页面/鼠标特效,选择写入 localStorage,优先级高于配置里的 default。

对应配置(无需改配置,值存在浏览器):

# localStorage 键(运行时写入,非 _config.yml)
# matery.effect.page   → 页面特效 id
# matery.effect.mouse  → 鼠标特效 id

4.3 全部可调项

键类型默认可选值/范围作用
effects.enablebooltruetrue / false特效总开关
effects.desktop_onlybooltruetrue / false是否只在桌面端注入
effects.page.defaultstringoffoff / random / available 中的任一 id页面特效默认项(单选)
effects.page.available.<id>.labelstring—任意显示名面板/菜单显示文案
effects.page.available.<id>.libstring—sakura ripples leaf snowdown snowflake buble canvas_nest ribbon ribbon_dynamic实际加载的库
effects.mouse.defaultstringoffoff / random / available 中的任一 id鼠标特效默认项(单选)
effects.mouse.available.<id>.labelstring—任意显示名面板/菜单显示文案
effects.mouse.available.<id>.libstring—clicklove popupText star fireworks实际加载的库

键名(<id>)可自定义,但 lib 必须落在上表列出的库标识内;其他 lib 值未验证。

4.4 边界与冲突

  • page 与 mouse 两组各自单选:同组内配多个只有 default 指定的那个生效。
  • desktop_only: true 时走 desktopGate 门控:宽度 > BP.fun(1400px,BP 未定义回落 992)且 localStorage viewCount > 1;desktop_only: false 跳过门控,移动端也加载。
  • 运行时面板写入 localStorage matery.effect.page / matery.effect.mouse,优先级高于配置里的 default。
  • 改 effects 段后必须 clean 构建(见「已知坑」坑 5)。

启用条件(desktopGate,desktop_only 开启时)

  • 桌面宽 > BP.fun(1400px,BP 未定义回落 992)
  • localStorage viewCount > 1(防首访即加载)
  • desktop_only: false 时跳过门控(移动端也加载)

测试断言:特效脚本按门控加载(windowWidth > BP.fun)+ 页面/mouse 互斥单选生效。

4.5 小结

  • 最小可用:effects.enable + page.default 一行选特效
  • 同组配多个没用:只有 default 生效
  • 桌面看不到:先看宽度是否 > 1400px,再看 viewCount(首访不加载)
  • 想改主意:用悬浮面板切,别反复改配置

── 国际化与架构 ──

注:本分区按阅读导航分组,§6–§8 功能上分别属于「UI 交互」「UI 交互」「代码与打印」。

5. 繁简转换

用途:页面繁体/简体一键切换。

学习路径:开开关 → 页脚按钮 → 选择如何记忆 → 全参数 → 边界与冲突

5.1 如何启用

效果:页脚出现"繁/简"切换链接(页面含 #translateLink),点击后整页文字在简繁之间转换(JS languageToggle,简繁字库映射)。

用户选择会写入 localStorage(键 targetEncoding_<host>,同时落 cookie),下次访问自动沿用。

对应配置(2026-08-16 迁移聚合至 preference 段,2026-09-08 全站语言配置统一):

preference:           # 语言类偏好聚合(原 footer.translate 已删除)
  translate:
    enable: true      # 繁简转换开关

5.2 常用选项

① 关闭入口

效果:不再输出 #translateLink,页脚看不到切换链接;但已保存的用户选择不会被清除。

对应配置:

preference:
  translate:
    enable: false

② 用户选择的记忆位置

效果:选择存在 cookie targetEncoding_<host>(不是 localStorage),清 cookie 后回到默认简体。

对应机制(无配置键,仅说明):

cookie: targetEncoding_<host>

5.3 全部可调项

键类型默认可选值/范围作用
preference.translate.enablebooltruetrue / false页脚「繁/简」切换按钮开关

原 footer.translate 已删除,未迁移的其他键名未在本文件出现,其他值未验证。

5.4 边界与冲突

  • 旧的 footer.translate 不再被读取 —— 残留该段不会报错,但不生效。
  • 只有 enable: true 才输出 #translateLink;关闭后已保存的选择不会被清除。
  • 选择存 cookie targetEncoding_<host>(非 localStorage);清 cookie 后回到默认简体。

5.5 小结

  • 只有一行配置:preference.translate.enable
  • 配了没反应:检查是否还在写已删除的 footer.translate
  • 转换后清不掉:清 targetEncoding_<host> cookie

测试断言:页面含 #translateLink 或切换按钮。


6. 阅读进度条 / 返回顶部

用途:阅读进度指示 + 一键回到顶部。

学习路径:开进度条 → 调高与颜色 → 开回顶 → 换库 → 全参数 → 边界

6.1 如何启用

效果:页面顶部出现一条细进度条,随滚动从左向右增长;右下角出现返回顶部按钮(点击平滑滚回顶部)。

对应配置:

fun_features:
  progressbar:
    enable: true
  # 返回顶部按钮
backTop:
  enable: true

6.2 常用选项

① 进度条高度

效果:顶部进度条厚度变化(3 即 3px)。

对应配置:

fun_features:
  progressbar:
    height_px: 3     # 纯数值,不要写 "3px"

② 进度条颜色

效果:进度条颜色变成所填的任意 CSS 颜色(本文件为 #29d 蓝色)。

对应配置:

fun_features:
  progressbar:
    color: "#29d"

③ 进度条库来源

效果:进度条基于 ScrollProgress 库实现,库地址可换公共 CDN 或本地路径;地址不可达时进度条直接缺失。

对应配置:

libs:
  js:
    scrollProgress: https://lib.baomitu.com/scrollprogress/3.0.2/scrollProgress.min.js

④ 动态内容后重算

效果:解密 / 翻页 / 下拉加载等内容变化后调用 refreshLayout(),销毁旧实例并重算 —— 避免监听器叠加导致进度计算错误。

对应机制(注册为布局回调,无配置键):

Matery.events.registerLayoutCallback(function () { /* 重算进度 */ });
Matery.events.refreshLayout();

6.3 全部可调项

键类型默认可选值/范围作用
fun_features.progressbar.enablebooltruetrue / false阅读进度条开关
fun_features.progressbar.height_pxnumber3像素数值(未带单位)进度条高度
fun_features.progressbar.colorstring"#29d"任意 CSS 颜色进度条颜色
backTop.enablebooltruetrue / false返回顶部按钮开关
libs.js.scrollProgressstring公共 CDN 地址(片段所示)CDN 或本地路径 /libs/scrollprogress/scrollProgress.min.js进度条库来源

6.4 边界与冲突

  • height_px 是纯数值(键名带 _px 后缀),不要写成 "3px"。
  • libs.js.scrollProgress 换成不可达地址时进度条直接缺失(无内置兜底实现)。
  • 两功能互相独立:关进度条不影响回顶,反之亦然;backTop 是顶层键,不在 fun_features 下。
  • 改本段后必须 clean 构建(见「已知坑」坑 5)。

测试断言:页面含 .progress-bar 或 #backTop;TC-L15 G6(tools/tests/core-events-integration.test.js,2 断言):布局回调注册 ≥1 且 refreshLayout() 不抛错。

6.5 小结

  • 两个功能、两个键位:fun_features.progressbar 与顶层 backTop,互不影响
  • 高度写错单位:height_px 只收数字
  • 进度条不动:先查 libs.js.scrollProgress 是否可达

7. 打赏弹窗

用途:文章打赏按钮 + 微信/支付宝二维码弹窗。

学习路径:开全局入口 → 换标题 → 配两个二维码 → 按篇覆盖 → 全参数 → 边界

7.1 如何启用

效果:文章底部出现"赏"按钮(页面含 #reward),点击弹出二维码 dialog,内含支付宝/微信 tabs,可点关闭按钮或点遮罩关闭。

对应配置:

post:
  reward:
    enable: true
    title: 码字辛苦,打赏作者!
    wechat: /medias_webp/reward/wechat.webp
    alipay: /medias_webp/reward/alipay.webp

7.2 常用选项

① 弹窗标题

效果:弹窗顶部标题变成所填文案(本文件为"码字辛苦,打赏作者!")。

对应配置:

post:
  reward:
    title: 码字辛苦,打赏作者!

② 两个收款码

效果:分别决定"微信"与"支付宝"tab 里显示的二维码图片;只配一个时另一个 tab 无图可展示(tab 是否隐藏未验证)。

对应配置:

post:
  reward:
    wechat: /medias_webp/reward/wechat.webp
    alipay: /medias_webp/reward/alipay.webp

③ 单篇覆盖全局

效果:front-matter 写 reward: true 即本篇开启打赏(哪怕全局关着);不写则跟随全局 post.reward.enable。

对应配置:

reward: true    # 开启本文打赏(可选,默认按全局)

7.3 全部可调项

键类型默认可选值/范围作用
post.reward.enablebooltruetrue / false全局打赏入口开关
post.reward.titlestring码字辛苦,打赏作者!(片段所示)任意字符串弹窗标题
post.reward.wechatstring—图片路径(建议 webp/png)微信收款二维码
post.reward.alipaystring—图片路径支付宝收款二维码
文章 front-matter rewardbool—true / false单篇覆盖全局开关

7.4 边界与冲突

  • front-matter 未写 reward 时按全局 post.reward.enable;写了以文章值为准。
  • 只配一个二维码时另一个 tab 无图可展示(tab 是否隐藏未验证)。
  • 图片路径是站点相对路径,走 CDN 替换;换成外链图片时需确认能直连。

7.5 小结

  • 全局开:post.reward.enable: true,再配两张二维码
  • 按篇控制:front-matter reward: true/false
  • 点开没图:检查路径是否被 CDN 替换成不可达地址

测试断言:页面含 #reward + 打赏按钮。


8. 打印样式

用途:打印文章时的排版优化。

学习路径:开开关 → 看打印预览 → 全参数 → 边界

8.1 如何启用

效果:只在 @media print 生效 —— 打印预览时隐藏导航/侧栏/页脚,正文居中留白优化,链接显示 URL;屏幕上完全看不出差别。

对应配置:

print:
  enable: true

8.2 常用选项

① 关闭打印优化

效果:浏览器打印回到页面原样 —— 导航/侧栏照旧打印出来,分页与留白都不优化。

对应配置:

print:
  enable: false

8.3 全部可调项

键类型默认可选值/范围作用
print.enablebooltruetrue / false打印样式开关

8.4 边界与冲突

  • 只作用于 @media print:屏幕上完全看不出差别,必须用浏览器打印预览验证。
  • 隐藏导航/侧栏/页脚是纯 CSS 规则,不改变 DOM,也不影响屏幕端交互。
  • 关掉后浏览器打印仍是页面原样(分页、留白都不会优化)。

8.5 小结

  • 只有一行:print.enable
  • 验证方式特殊:必须看打印预览,别在屏幕上找差异
  • 零风险:纯 CSS,不影响屏幕端

测试断言:CSS 含 @media print 规则。


── 媒体与数据可视化 ──

注:本分区按阅读导航分组,§13–§14 属于「UI 交互」,§15/§18 属于「架构」,§16–§17 属于「UI 交互」。

9. 音乐播放器 APlayer

用途:文章/侧边栏嵌入音乐播放器(MetingJS 解析 + APlayer 播放)。

学习路径:开开关 → 选音源与类型 → 填 id → 吸底 → 全参数 → 边界

9.1 如何启用

效果:页面出现音乐卡片(封面 + 播放控制 + 进度条,页面含 aplayer 容器标记),暗色模式自动适配。

对应配置:

music:
  enable: true
  server: netease        # netease/tencent/kugou/xiami/baidu
  type: playlist         # song/playlist/album/search/artist
  id: 190133732          # 网易云歌单/歌曲 ID

9.2 常用选项

① 音源与解析类型

效果:server 决定去哪个平台解析,type 决定 id 的含义 —— playlist + 歌单 ID 得到列表,song + 歌曲 ID 得到单曲。两者必须成对。

对应配置:

music:
  server: netease
  type: playlist
  id: 190133732

② 吸底模式

效果:fixed: true 时播放器固定在页面底部,与卡片内嵌形态互斥(同一时刻只有一种)。

对应配置:

music:
  fixed: false           # true = 吸底模式

③ 自动播放

效果:autoplay: true 尝试自动开播;但受浏览器自动播放策略限制,无用户交互时通常不会真正发声。

对应配置:

music:
  autoplay: false

④ 主题色

效果:播放器控件主题色变成所填 CSS 颜色(本文件 #42b983 绿)。

对应配置:

music:
  theme: '#42b983'

9.3 全部可调项

键类型默认可选值/范围作用
music.enablebooltruetrue / false音乐播放器开关
music.serverstringneteasenetease / tencent / kugou / xiami / baidu音源
music.typestringplaylistsong / playlist / album / search / artist解析类型(决定 id 的含义)
music.idstring | number—对应 type 的 ID/关键词歌单/歌曲/专辑/歌手 ID
music.fixedboolfalsetrue / false吸底模式
music.autoplayboolfalsetrue / false自动播放
music.themestring'#42b983'任意 CSS 颜色播放器主题色

9.4 边界与冲突

  • type 与 id 必须成对:把 playlist 改成 song 而沿用歌单 ID,会解析不到歌曲。
  • fixed: true 时播放器固定在页面底部,与卡片内嵌形态互斥(同一时刻只有一种)。
  • autoplay: true 会受浏览器自动播放策略限制,无用户交互时通常不会真正发声。
  • 第三方音源可用性受上游影响,xiami 等服务端已关停,配置仍可写但可能无结果(未在本文件验证)。

9.5 小结

  • 最小可用:enable + server + type + id 四项
  • 换了类型记得换 id:type/id 是成对的
  • 不能自动播放:正常现象,浏览器策略限制

测试断言:页面含 aplayer 容器标记。


10. 视频播放器 DPlayer

用途:文章内嵌视频播放器(支持 HLS/直播等)。

学习路径:开开关 → 写 tag → 全参数 → 边界

10.1 如何启用

效果:正文出现视频播放器(播放/暂停/进度/音量,支持弹幕),页面含 dplayer 容器标记。

对应配置:

dplayer:
  enable: true

10.2 常用选项

① 指定视频源

效果:播放器加载 url 指向的视频;写本地路径则播本地文件。

对应配置(正文里写 tag,不是 YAML):

{% dplayer url=/medias_webp/video/demo.mp4 %}

10.3 全部可调项

键类型默认可选值/范围作用
dplayer.enablebooltruetrue / falseDPlayer 资源加载与 tag 渲染开关
tag 参数 urlstring—视频地址(本地或远程)视频源

tag 的其他参数(弹幕等)未在本文件出现,其他值未验证。

10.4 边界与冲突

  • dplayer.enable: false 时 tag 不输出播放器(连容器都没有),不是"显示空白播放器"。
  • 示例里的 tag 是正文渲染内容,本身不受本篇配置影响 —— 配置是站点级的。
  • 本地视频路径写错时播放器仍会渲染,只是视频 404(表现为黑屏)。

10.5 小结

  • 站点级开关 + 正文 tag 两件事,别混为一谈
  • 黑屏先查路径:播放器渲染成功 ≠ 视频存在
  • 关掉是彻底不渲染:不是留一个空播放器

测试断言:页面含 dplayer 容器标记。


11. Bilibili 视频卡片

用途:嵌入 Bilibili 视频(iframe 或卡片)。

学习路径:开开关 → 写 BV 号 → 可选覆盖地址 → 全参数 → 边界

11.1 如何启用

效果:正文出现 Bilibili 播放器 iframe,页面含 bilibili 相关容器标记。

对应配置:

bilibili:
  enable: true

11.2 常用选项

① 按 BV 号嵌入

效果:tag 里的 BV 号决定播放哪个视频(本文件示例即如此)。

对应配置(正文里写 tag):

{% bilibili BV1oa4y1L7mw %}

② 统一覆盖播放器地址

效果:配了 iframeUrl 则以它为准,忽略 tag 传来的 BV 号(适合固定嵌入某个直播/播放页)。

对应配置:

bilibili:
  # iframeUrl: //player.bilibili.com/player.html?aid=xxx&bvid=xxx

iframeUrl 在本文件的片段里是注释状态,启用方式与其他值未验证。

11.3 全部可调项

键类型默认可选值/范围作用
bilibili.enablebooltruetrue / falseBilibili 卡片/tag 开关
bilibili.iframeUrlstring—(片段中为注释)完整播放器 URL可选:覆盖 tag 生成的地址

iframeUrl 在本文件的片段里是注释状态,启用方式与其他值未验证。

11.4 边界与冲突

  • 不配 iframeUrl 时按 tag 传入的 BV 号工作(本文件示例即如此);配了则以 iframeUrl 为准。
  • enable: false 时 tag 不渲染,正文只留空行。
  • 播放器是 iframe,受上游地区/Referer 策略影响,本地预览可能显示黑屏。

11.5 小结

  • 两种用法:按 BV 号(默认)或全局 iframeUrl 覆盖
  • 本地黑屏:常见现象,属上游策略而非配置错误
  • 关掉留空行:正文会出现一段空白

测试断言:页面含 bilibili 相关容器标记。


12. ECharts 图表

用途:文章内嵌 ECharts 交互图表。

学习路径:开开关 → 写 tag(宽/高 + JSON)→ 明暗跟随 → 全参数 → 边界

12.1 如何启用

效果:正文出现可交互图表(柱状/折线/饼图等),容器高度固定占位(防 CLS),切换明暗主题时图表自动重建配色。

对应配置:

echarts:
  enable: true

12.2 常用选项

① 宽高 + 图表配置

效果:第一个参数是容器宽度('100%' 即占满正文宽),第二个参数是容器高度(400 即 400px),后面是 ECharts option JSON。

对应配置(正文里写 tag):

{% echarts '100%' 400 %}
{
  "title": {"text": "示例图表"},
  "xAxis": {"type": "category", "data": ["A", "B", "C"]},
  "series": [{"data": [10, 20, 30], "type": "bar"}]
}
{% endecharts %}

② 明暗主题自动切换

效果:切换明暗主题时,图表 dispose 后按新主题 reinit 再 setOption —— 深色页面上不会留着浅色坐标轴。

对应机制(走统一入口 Matery.echarts.init,无配置键):

Matery.echarts.init(id, option);   // 内部监听 theme-changed

12.3 全部可调项

键类型默认可选值/范围作用
echarts.enablebooltruetrue / falseECharts 库与 tag 开关
tag 第 1 参数string—CSS 宽度(示例 '100%')容器宽度
tag 第 2 参数number—像素高度(示例 400)容器高度

12.4 边界与冲突

  • 高度由 tag 第二参数固定(容器先占位,防 CLS),图表不会撑高容器。
  • 只有走 Matery.echarts.init(id, option) 的图表才随明暗切换 dispose→reinit;自己 echarts.init 的不会跟随主题。
  • enable: false 时 tag 的输出形态未在本文件验证,但 Matery.echarts 入口不会注册。

明暗主题自动切换范围(2026-09-06 P11 统一)

主题内部全部 ECharts 图表(文章 tag / 词云 / 雷达图 / 文章统计 3 图 / 日历 / 音乐)统一走 Matery.echarts.init(id, option) —— 监听 theme-changed 事件,切换明暗时自动 dispose + reinit(新主题)+ setOption。容器 CSS 固定高度占位(防 CLS)。

测试断言:页面含 echarts 容器标记 + Matery.echarts 已注册(tools/tests/wordcloud.test.js L2g 验证明暗切换)。

12.5 小结

  • 两件事都要:站点开 echarts.enable,正文写 tag
  • 高度是固定的:图表超高不会撑开容器,需要自己调第二个参数
  • 不跟明暗:多半是没用 Matery.echarts.init 而是自己 init

13. AOS 卡片进入动画

用途:首页瀑布流卡片加载时的进入动画。

学习路径:看效果 → 了解触发方式 → 参数位置 → 边界

13.1 如何启用

效果:新卡片(infScroll 下拉加载出来的)进入视口时淡入上移(fade-in-up),已经在视口内的旧卡片不重播。

对应配置:默认启用,无开关;参数在 themes/matery/source/js/boot.js(AOS duration 700ms / delay 100ms,片段值,其他值未验证)。

13.2 实现方式

效果:只有滚动到视口才播动画 —— 靠 IntersectionObserver 监听 .card,进入时才加 .card-aos-enter 类;.article 不加(Masonry 绝对定位,避免重叠)。

对应机制(无 YAML 键):

IntersectionObserver 监听 .card → 进入视口 → 加 .card-aos-enter(fade-in-up, 500ms)
.article 排除在外(Masonry 绝对定位)

13.3 全部可调项

项位置取值(片段)作用
aos.durationthemes/matery/source/js/boot.js700ms动画时长(其他值未验证)
aos.delaythemes/matery/source/js/boot.js100ms动画延迟(其他值未验证)

13.4 边界与冲突

  • 只作用于 .card,.article 被排除 —— 否则 Masonry 绝对定位会重叠。
  • 卡片动画类自身写的是 500ms(fade-in-up),AOS 全局参数是 700ms / 100ms,两处数值并存,以实际 CSS/JS 为准。

13.5 小结

  • 没有 YAML 开关:默认开,参数在 boot.js
  • 新卡片才播:靠 IntersectionObserver,不是 CSS 一上来就跑
  • 关联 §15:内容动态加载后由 refreshLayout() 重新接管

测试断言:下拉加载后新卡片含 .card-aos-enter,且卡片无重叠(tools/tests/infinite-scroll-aos.test.js)。


14. 悬浮面板(right-floating)

用途:右下角齿轮按钮打开的"偏好设置"面板 —— 字体缩放、语言切换(简/繁)、显示模式(亮/自动/暗)、页面特效开关等,选择保存在 localStorage,跨页面持久化。

学习路径:点齿轮 → 字体缩放 → 语言 → 背景 → 持久化 → 边界

14.1 如何启用

效果:面板默认隐藏,点击右下角齿轮按钮(.btn-floating)以 flex 展开,再次点击收起;面板分区:字体 / 语言 / 显示模式 / 特效 / 背景。

对应配置:面板为纯前端组件(layout/_partial/common/right-floating.ejs + floating-panel.styl),无独立配置开关;面板内各选项与主题既有功能联动(语言走 lang.translate、显示模式走 data-user-color-scheme、特效走 effects 开关)。

14.2 常用选项

① 字体缩放

效果:A+ / A− 每步 0.1,范围 0.85–1.3,即时作用于根节点 --font-scale;↺ 一键恢复 1.0;刷新/跨页保持。

对应配置(运行时写 localStorage,非 YAML):

matery.font-scale    # 0.85 ~ 1.3,步进 0.1,默认 1.0

② 语言区

效果:语言下拉(含国旗,行宽不足时只显国旗)+ 简/繁分段,写入本地偏好并跳转对应语言版。

对应配置:无独立键位 —— 走主题既有语言配置(简体/繁体各自的站点版本)。

③ 背景区

效果:网页背景可选 off / 图片 / 视频;可选项由 background.image.enable / background.video.enable 控制,两者都关只剩 off。

对应配置:

matery.bg            # off | image | video(运行时偏好)

14.3 全部可调项(面板控件)

控件持久化键取值/范围作用
字体缩放matery.font-scale0.85–1.3,步进 0.1根节点 --font-scale
背景模式matery.bgoff / image / video网页背景(互斥单选)
简/繁切换—(未在本文件列出)简体 / 繁体跳转对应语言版
显示模式—(未在本文件列出)亮 / 自动 / 暗data-user-color-scheme
页面特效matery.effect.page / matery.effect.mouse见 §4切换特效

未列出的持久化键名未在本文件出现,其他值未验证。

14.4 边界与冲突

  • 面板自身没有总开关;显隐由各分区对应的功能开关间接控制(effects.enable / background.enable)。
  • 字体缩放写的是 CSS 变量 --font-scale,不是 font-size —— 直接改 font-size 会和面板打架。
  • localStorage 里残留的偏好优先于配置默认值(如 matery.bg 优先 bgDefault)。

14.5 小结

  • 无配置入口:要改默认行为去改各功能自己的配置,别找面板开关
  • 持久化在 localStorage:清理浏览器数据即回到默认
  • 字体缩放走 CSS 变量:--font-scale 是单一出口

测试断言:TC-L14(tools/tests/floating-panel-integration.test.js,8 断言,归 release-test L11):面板默认隐藏 / 齿轮打开 / 字体缩放 / 恢复默认等。


15. 事件总线(Matery.events)

用途:主题内部组件通信的统一事件总线,解决"内容动态加载后组件需重新初始化"的问题 —— 解密、翻页、下拉加载等场景触发对应刷新,各组件注册回调即可,无需互相耦合。

学习路径:注册回调 → 触发刷新 → 区分全量/布局 → API 全表 → 边界

15.1 如何启用

效果:注册的回调在对应刷新时被调用 —— 全量刷新会让 MathJax/mermaid/Prism 重新渲染,布局刷新只重排(AOS/Masonry/进度条),两者互不触发。

对应配置(themes/matery/source/js/events.js):

// 内容动态加载后需要重渲染 → 全量刷新
Matery.events.registerRefreshCallback(function () { /* 重渲染 */ });
// 仅布局变化(resize/内容高度变化)→ 轻量布局刷新
Matery.events.registerLayoutCallback(function () { /* 重排 */ });
Matery.events.refreshLayout();

15.2 常用选项

① 全量刷新(重渲染内容)

效果:触发后所有 registerRefreshCallback 注册的回调依次执行 —— 用于解密后、翻页后重新渲染公式/图表/代码高亮。

对应配置:

Matery.events.registerRefreshCallback(cb);
Matery.events.refresh();

② 布局刷新(只重排,不重渲染)

效果:只跑 registerLayoutCallback 的回调,不重复触发布局无关的重渲染 —— 比 refresh 轻,适合窗口 resize、内容高度变化。

对应配置:

Matery.events.registerLayoutCallback(cb);
Matery.events.refreshLayout();

15.3 全部可调项(API)

方法作用
Matery.events.registerRefreshCallback(cb)注册全量刷新回调(内容重渲染:MathJax/mermaid/Prism 等)
Matery.events.registerLayoutCallback(cb)注册布局刷新回调(仅重算布局:AOS/Masonry/进度条)
Matery.events.refresh()触发全部 refresh 回调
Matery.events.refreshLayout()触发全部 layout 回调(轻量,不重渲染内容)

15.4 边界与冲突

  • refresh 与 refreshLayout 隔离:全量刷新不重复触发布局,布局刷新不重渲染内容。
  • 解密后统一走 refresh(见内容 tag 篇 §14 / 布局篇 §11)。
  • 回调里再做重活要注意幂等 —— 重复触发时不能重复绑定监听器(参考 §1.4 codeWidget 的教训)。

15.5 小结

  • 先想清楚要哪种:内容变了 → refresh;只是尺寸变了 → refreshLayout
  • 轻量优先:能用 refreshLayout 就别用 refresh
  • 注册即生效:不需要额外的初始化步骤

测试断言:TC-L15 G3(tools/tests/core-events-integration.test.js,4 断言):API 存在 / refresh 触发全量 / refreshLayout 触发布局 / 隔离性。


16. Banner 明暗切换

用途:Banner 背景随明暗主题切换联动 —— theme-changed 事件派发后,body 背景在明暗两套样式间切换;背景模式(图片/视频/关闭)由面板偏好 matery.bg 控制。

学习路径:切明暗看联动 → 选背景模式 → 设默认值 → 全参数 → 边界

16.1 如何启用

效果:点击显示模式切换(亮/暗)后,Banner 与 body 背景同步换色 —— 不会出现"文字变白了但背景还是白的"。

对应配置:

bgDefault: image      # 无本地偏好时的默认背景模式(off / image / video)

16.2 常用选项

① 运行时背景模式

效果:在悬浮面板选背景模式,选择存 localStorage matery.bg,优先级高于 bgDefault;清 localStorage 后回落配置值。

对应配置:

matery.bg    # off | image | video(互斥单选,图片/视频二选一)

② 面板里哪些背景可选

效果:background.image.enable / background.video.enable 关掉后,面板对应选项不可选;两者都关只剩 off。

对应配置:

background:
  enable: true
  image:
    enable: true
  video:
    enable: true

16.3 全部可调项

键类型默认可选值/范围作用
bgDefaultstring—off / image / video无本地偏好时的默认背景模式
matery.bg(localStorage)string—off / image / video运行时背景偏好(互斥单选)
background.enablebool—true / false面板「背景区」总开关
background.image.enablebool—true / false面板「图片」选项是否可选
background.video.enablebool—true / false面板「视频」选项是否可选

背景图片/视频的具体地址键未在本文件展开,其他值未验证。

16.4 边界与冲突

  • matery.bg(本地偏好)优先于 bgDefault;清除 localStorage 后回落到配置值。
  • background.image.enable / background.video.enable 关掉后,面板对应选项不可选;两者都关只剩 off。
  • 联动靠 theme-changed 事件:手动改 data-user-color-scheme 而不派发事件,Banner 背景不会跟着变。

16.5 小结

  • 默认值在 bgDefault,用户选择在 localStorage,后者优先
  • 联动靠事件不是靠 CSS:绕过 theme-changed 就不会同步
  • 想彻底关背景区:background.enable: false

测试断言:tools/tests/banner-bg.test.js T5:body 背景明暗变化(theme-changed 派发)。


17. 阅读模式与代码全屏(2026-09-06 分离为两个独立功能)

用途:

  • 阅读模式(read_mode):文章卡片一键全屏沉浸阅读,隐藏页面其他元素
  • 代码全屏(code-fullscreen):单个代码块容器全屏查看,与阅读模式相互独立(类加在代码容器而非卡片)

学习路径:进阅读模式 → 看悬浮球 → 退出动画 → 代码全屏 → 展开机制 → 边界

17.1 如何启用

效果:文章信息栏(post-info)点阅读模式按钮(#read_mode),整个文章卡片铺满屏幕(.card-block-fullscreen),页面其他元素被隐藏;再点一次退出。代码块工具栏的全屏按钮(.code-area .code-fullscreen)则只让该代码容器全屏(.code-area.code-block-fullscreen)。

对应配置:两个按钮都是内置 UI,无 YAML 开关;行为由 layout 与 styl 决定。

17.2 常用选项

① 进入动画与悬浮球

效果:卡片以 elastic 1s 弹入;悬浮球延迟淡入(readmode-ball-fade .3s ease .75s both)—— elastic transform 会建立 containing block 让 fixed 悬浮球跳动,延迟淡入正好避开。

对应机制:

.card-block-fullscreen            { animation: elastic 1s; }
readmode-ball-fade                { .3s ease .75s both }
悬浮球                            { position: fixed; right: 1em; top: 70px; z-index: 10000 }

top: 70px 避开导航栏 bottom 64;z-index: 10000 高于导航栏 997。

② 退出动画

效果:退出时 card-block-fullscreen-exit 淡出(scale .98 + opacity 0),220ms 后才移除全屏类 —— 否则悬浮球会瞬间跳回原位。

对应机制:

exit 类 → 淡出(scale .98 + opacity 0)→ 220ms → 移除全屏类

③ 代码块展开(与 §1 限高联动)

效果:点展开条后 pre.style.maxHeight = pre.scrollHeight + 'px'(完整高度,无内部滚动条,页面滚动);收起时 maxHeight='',恢复 --code-max-height 450px。

对应机制:

pre.style.maxHeight = pre.scrollHeight + 'px';   // 展开
pre.style.maxHeight = '';                        // 收起 → 回到 450px

17.3 全部可调项

项位置值(片段)作用
卡片全屏类layout / styl.card-block-fullscreen阅读模式全屏
悬浮球定位stylright: 1em; top: 70px; z-index: 10000避开导航栏、盖在其上
退出类styl.card-block-fullscreen-exitscale .98 + opacity 0
代码全屏类styl.code-area.code-block-fullscreen只全屏单个代码块

以上为样式类名与数值,改它们属于改源码,不是改配置。

17.4 边界与冲突

  • 阅读模式与代码全屏是两个独立类:进阅读模式不会让代码块全屏,反之亦然。
  • 悬浮球必须延迟淡入 —— 去掉延迟会看到悬浮球跳动(elastic 建立 containing block)。
  • 退出动画必须等 220ms 再移除类,否则悬浮球跳回。
  • z-index: 10000 是硬编码值,导航栏是 997;改导航栏层级时要同步检查这里。

17.5 小结

  • 两个功能别混:卡片全屏 vs 代码容器全屏
  • 动画时序是刚需:延迟淡入 + 退出等 220ms,删掉就跳
  • 与代码块增强联动:展开改用 scrollHeight,不受 450px 限制

测试断言:tools/tests/readmode-integration.test.js(L2f PASS=14):阅读模式进入/退出、悬浮球、代码全屏、展开后代码完整显示。


18. JS 加载分层与去 jQuery(2026-09-05 P4/P5)

用途:移除全站 jQuery 依赖(原生 DOM API 重写),并按首屏优先级分层加载脚本,降低首屏阻塞。

学习路径:看副作用 → 确认 jQuery 已停用 → 看分层策略 → 边界

18.1 如何启用

效果:页面不再请求全局 jQuery 库;核心脚本带 defer 不阻塞首屏解析;统计脚本 async;首屏关键内联脚本同步注入,先于所有 defer 执行。

对应配置:

libs:
  js:
    # jquery: ...          # 已注释停用(P4/P5 全站去 jQuery 完成)
    # jqueryUI: ...        # 已注释停用
    # jqueryBarrager: ...  # 已注释停用
    jqueryPjax: ...        # 保留(独立库,非全局 jQuery)

18.2 常用选项

① 分层策略

效果:核心脚本延后但不阻塞解析,统计类完全不参与首屏,内联关键脚本抢在最前 —— 保证依赖顺序又不等网络。

对应配置:

核心脚本(materialize/masonry/imagesloaded/aos/events/plugins)→ defer
统计类(umami/busuanzi)                                      → async
首屏关键脚本                                                  → 内联同步(先于 defer)

② 特效库原生重写

效果:ripples 特效用原生重写,去掉了对 jQuery 的依赖(contact 页已删除)。

对应机制:见 §4 的 effects.mouse / effects.page 配置,行为不变、实现不依赖 jQuery。

18.3 全部可调项

项位置取值(片段)作用
libs.js.jquery主题 _config.yml已注释全局 jQuery(停用)
libs.js.jqueryUI主题 _config.yml已注释jQuery UI(停用)
libs.js.jqueryBarrager主题 _config.yml已注释弹幕库(停用)
libs.js.jqueryPjax主题 _config.yml保留独立库,非全局 jQuery
核心脚本 deferlayout统一 defer不阻塞首屏解析
统计脚本 asynclayout统一 async不参与首屏
首屏关键脚本layout内联同步先于 defer 执行

18.4 边界与冲突

  • 停用 jQuery 后,任何依赖 $ / jQuery 的内联脚本或第三方插件都会报错 —— 加新库前先确认它是否自带 jQuery 依赖。
  • defer 保证按文档顺序执行,但不保证在 DOMContentLoaded 之前 —— 依赖顺序敏感的逻辑要么内联,要么显式监听事件。
  • 分层是全局策略,不是逐页开关。

18.5 小结

  • jQuery 已全站移除:libs.js.jquery* 三段是注释状态,不是可用开关
  • 新增脚本先想优先级:核心 defer / 统计 async / 首屏内联
  • jqueryPjax 是例外:名字里有 jQuery,但它是独立库

测试断言:页面无全局 jQuery 请求;核心脚本带 defer。


⚠️ 已知坑

坑 1:标题编号双重叠加

现象:标题渲染为「1. 1. 概述」(两个编号)。

原因:主题 CSS 自动给 h2–h6 加编号(默认开启),手写编号(如 ## 1. 概述)会叠加。

正确做法:手写编号的页面在 front-matter 加 closeAutoTocNum: true;不手写编号的页面不要加该字段。

本文已正确设置 closeAutoTocNum: true。

坑 5:改配置后必须 clean 构建

现象:改了 effects/subtitle.typed/image_zoom 等配置但页面不变。

原因:Hexo 缓存机制不会自动检测配置变更。

正确做法:改配置后必须 npm run clean && npm run build。仅改文章内容(如图片/文字)不需要 clean,增量构建正常工作。


附:交互视觉功能速查表

功能配置键参数要点自动化断言标记
代码块codelanguage/copy_btn/show_fullcode-area
灯箱image_zoom + libs.js.lightgalleryenable.img-item / .lg-outer
打字机subtitle.typed / post.typedloop/showCursor/速度#typed
特效sakura 等 10+ 开关桌面+访问>2 门控windowWidth > BP.fun
繁简lang.translate.enable聚合配置(原 zh_default/footer.translate 删除)#translateLink
进度条progressbarheight/color.progress-bar
回顶backTopenable#backTop
打赏post.rewardwechat/alipay 图#reward
打印printenable@media print
APlayermusicserver/type/idaplayer
DPlayerdplayerurldplayer
BilibilibilibiliiframeUrlbilibili
EChartsechartsJSON 配置echarts
AOS 动画aos(boot.js)duration/delay.card-aos-enter
悬浮面板right-floating(ejs)字体缩放/语言/主题/特效#floating-panel
事件总线Matery.eventsrefresh/refreshLayoutMatery.events
Banner 明暗matery.bg(localStorage)off/image/videobody 背景
Wiki 行号prism line-numberswiki 页代码块.line-numbers
阅读模式#read_mode(post-info 按钮)卡片全屏 + 悬浮球.card-block-fullscreen
代码全屏.code-area .code-fullscreen容器全屏(独立于阅读模式).code-block-fullscreen
JS 加载分层libs.js(jquery 注释停用)核心 defer / 统计 async / 首屏内联同步无全局 jQuery 请求

参考&致谢

系列教程

全部文章RSS订阅

Hexo 主题功能测试系列


Hexo主题功能测试-交互视觉篇
发布于
2026年8月7日
许可协议。转载请注明来源
赏
评论
数据加载中 ...
 上一篇

阅读全文

Hexo主题功能测试-布局与页面篇
Hexo主题功能测试-布局与页面篇 Hexo主题功能测试-布局与页面篇
主题布局与页面功能完整教程与测试:文章布局特性(上下篇/版权/时效/TOC/广告)、侧边栏组件(雷达图/标签云/词云/归档/关于页)、响应式断点、相册、搜索、评论、暗色模式、加密、RSS/站点地图、PWA。每项先看效果、再看对应配置,供自动
2026-08-07
下一篇 

阅读全文

Hexo主题功能测试-内容tag篇
Hexo主题功能测试-内容tag篇 Hexo主题功能测试-内容tag篇
主题内容 tag 插件完整教程与测试:note 便签、timeline 时间线、tabs 标签页、label 行内标签、button 按钮、githubCard 卡片、mermaid 图、pdf 嵌入、insertmd 片段、wechat_
2026-08-07