本文既是 matery 主题交互视觉功能的完整使用教程,也是 自动化测试靶场。覆盖:代码块增强、图片灯箱、打字机、页面特效、繁简转换、进度条、回顶、打赏、打印。
── 代码与打印 ──
1. 代码块增强
用途
代码块显示语言标签、提供复制/展开/折叠/全屏操作,超长代码自动限高。
配置(主题 _config.yml 的 code 块)
code:
# 代码块语言标签(默认 TEXT,未识别的语言显示 TEXT)
language:
enable: true
default: "TEXT"
# 复制按钮
copy_btn: true
# 展开/折叠按钮(超长代码)
show_full: true
# 主动折叠按钮
shrink: true
# 代码块最大高度(超过则折叠,带单位字符串)
height_limit: "450px"用法
标准 Markdown 代码块即可(自动增强):
```bash
# Bash 示例
echo "Hello Matery"
```示例(多语言)
# 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# 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}")实现效果
- 右上角语言标签(bash/python/js/yaml)
- 复制按钮(点击复制代码)
- 超长代码显示"展开"按钮
- 全屏按钮(代码大屏查看)
测试断言:页面含
code-area标记(≥4 个代码块)。
展开机制(code-area)
代码块限高与展开由 code-area 组件统一处理:
- 限高:
code.height_limit(默认"450px")——超过该高度的代码块自动折叠 - 展开:折叠态底部显示
scroll-down-bar展开条,点击后 JS 将容器maxHeight设为scrollHeight(完整显示,不再限高) - 横向滚动:代码容器
overflow-x: auto,超宽行横向滚动不换行(配合code.break: false) - 全屏:
code.show_expand: true提供全屏查看
测试断言:readmode 用例(L11)验证展开后代码完整显示。
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 行号。
── UI 交互与动效 ──
2. 图片灯箱 lightGallery
用途
文章图片点击放大浏览,支持缩放/翻页/下载。
配置(主题 _config.yml)
# 文章图片自动被 articleInit 包装为 .img-item
image_zoom:
enable: true图片尺寸注入前置(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 时已有尺寸属性,灯箱打开不触发重排。
用法
普通 Markdown 图片即可(自动增强):
示例


实现效果
- 图片 hover 阴影 + 边框
- 点击弹出灯箱(全屏 + 缩放 + 翻页)
- 支持字幕(alt/title 显示)
测试断言:图片被包装为
.img-item,点击弹出.lg-outer。
3. 打字机 Typed
用途
Banner 副标题/文章标题逐字打字动画。
配置(主题 _config.yml)
subtitle:
enable: true
typed:
enable: true # 启用打字机
loop: true # 循环轮播
showCursor: true # 显示光标
cursorChar: "_" # 光标字符
startDelay: 100 # 启动延迟(ms)
typeSpeed: 80 # 打字速度(ms/字)
backSpeed: 50 # 删除速度(ms/字)
post:
typed:
enable: true # 文章标题打字机实现效果
- Banner 副标题逐字打出
- 文章页标题打字效果
- 光标闪烁 + 循环轮播
测试断言:页面含
#typed或.typed-cursor标记。
4. 页面特效
用途
装饰特效:页面/背景特效(樱花/水波/落叶/雪花/网络/彩带等)与鼠标/点击特效(爱心/星星/烟花等),互斥单选。
配置(主题 _config.yml 的 effects 块)
effects:
enable: true # 总开关
desktop_only: true # 是否只在桌面端注入
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 }
mouse: # 鼠标/点击特效(互斥,选一个)
default: off
available:
clicklove: { label: 爱心, lib: clicklove }
popupText: { label: 弹出文字, lib: popupText }
mouseStar: { label: 星星, lib: star }
fireworks: { label: 爆炸, lib: fireworks }运行时可从右侧悬浮面板切换特效(localStorage
matery.effect.page/matery.effect.mouse),无需改代码。
启用条件(desktopGate,desktop_only 开启时)
- 桌面宽 >
BP.fun(1400px,BP 未定义回落 992) - localStorage
viewCount> 1(防首访即加载) desktop_only: false时跳过门控(移动端也加载)
实现效果
页面装饰动画,桌面端体验增强,移动端自动关闭(性能)。
测试断言:特效脚本按门控加载(
windowWidth > BP.fun)+ 页面/mouse 互斥单选生效。
── 国际化与架构 ──
注:本分区按阅读导航分组,§6–§8 功能上分别属于「UI 交互」「UI 交互」「代码与打印」。
5. 繁简转换
用途
页面繁体/简体一键切换。
配置(主题 _config.yml,2026-08-16 迁移聚合至 preference 段,2026-09-08 全站语言配置统一)
preference: # 语言类偏好聚合(原 footer.translate 已删除)
translate:
enable: true # 繁简转换开关实现效果
- 页脚"繁/简"切换按钮
- 点击全局转换文字(JS languageToggle,简繁字库映射)
- localStorage 记忆用户选择(
targetEncoding_<host>cookie)
测试断言:页面含
#translateLink或切换按钮。
6. 阅读进度条 / 返回顶部
用途
阅读进度指示 + 一键回到顶部。
配置(主题 _config.yml)
fun_features:
progressbar:
enable: true
height_px: 3
color: "#29d"
# 返回顶部按钮
backTop:
enable: true进度条库配置(libs.js.scrollProgress)
进度条基于 ScrollProgress 库实现,库地址在主题 _config.yml 的 libs.js.scrollProgress 配置(默认走公共 CDN,可换本地 /libs/scrollprogress/scrollProgress.min.js):
libs:
js:
scrollProgress: https://lib.baomitu.com/scrollprogress/3.0.2/scrollProgress.min.jsrefreshLayout 联动:进度条实例注册为布局回调(Matery.events.registerLayoutCallback),内容动态加载(解密/翻页/下拉加载)后调用 refreshLayout() 会销毁旧实例并重算(避免监听器叠加导致进度计算错误)。
测试断言:TC-L15 G6(
tools/tests/core-events-integration.test.js,2 断言):布局回调注册 ≥1 且refreshLayout()不抛错。
实现效果
- 顶部进度条随滚动增长
- 右下角返回顶部按钮(带平滑滚动)
- 移动端按钮尺寸自适应
测试断言:页面含
.progress-bar或#backTop。
7. 打赏弹窗
用途
文章打赏按钮 + 微信/支付宝二维码弹窗。
配置(主题 _config.yml 的 post.reward)
post:
reward:
enable: true
title: 码字辛苦,打赏作者!
wechat: /medias_webp/reward/wechat.webp
alipay: /medias_webp/reward/alipay.webp文章 front-matter 控制
reward: true # 开启本文打赏(可选,默认按全局)实现效果
- 文章底部"赏"按钮
- 点击弹出二维码 dialog(支付宝/微信 tabs)
- 关闭按钮 + 点击遮罩关闭
测试断言:页面含
#reward+ 打赏按钮。
8. 打印样式
用途
打印文章时的排版优化。
配置(主题 _config.yml)
print:
enable: true实现效果
- 打印时隐藏导航/侧栏/页脚
- 正文居中 + 优化留白
- 链接显示 URL
测试断言:CSS 含
@media print规则。
── 媒体与数据可视化 ──
注:本分区按阅读导航分组,§13–§14 属于「UI 交互」,§15/§18 属于「架构」,§16–§17 属于「UI 交互」。
9. 音乐播放器 APlayer
用途
文章/侧边栏嵌入音乐播放器(MetingJS 解析 + APlayer 播放)。
配置(主题 _config.yml)
music:
enable: true
server: netease # netease/tencent/kugou/xiami/baidu
type: playlist # song/playlist/album/search/artist
id: 190133732 # 网易云歌单/歌曲 ID
fixed: false # true = 吸底模式
autoplay: false
theme: '#42b983'实现效果
- 音乐卡片(封面 + 播放控制 + 进度条)
- 吸底模式(fixed)固定页面底部
- 暗色模式适配
测试断言:页面含
aplayer容器标记。
10. 视频播放器 DPlayer
用途
文章内嵌视频播放器(支持 HLS/直播等)。
配置(主题 _config.yml)
dplayer:
enable: true示例(本地视频)
{% dplayer url=/medias_webp/video/demo.mp4 %}实现效果
- 视频播放器(播放/暂停/进度/音量)
- 支持弹幕(danmaku)
测试断言:页面含
dplayer容器标记。
11. Bilibili 视频卡片
用途
嵌入 Bilibili 视频(iframe 或卡片)。
配置(主题 _config.yml)
bilibili:
enable: true
# iframeUrl: //player.bilibili.com/player.html?aid=xxx&bvid=xxx示例
{% bilibili BV1oa4y1L7mw %}实现效果
Bilibili 播放器嵌入,可调整尺寸。
测试断言:页面含 bilibili 相关容器标记。
12. ECharts 图表
用途
文章内嵌 ECharts 交互图表。
配置(主题 _config.yml)
echarts:
enable: true示例
{% echarts '100%' 400 %}
{
"title": {"text": "示例图表"},
"xAxis": {"type": "category", "data": ["A", "B", "C"]},
"series": [{"data": [10, 20, 30], "type": "bar"}]
}
{% endecharts %}实现效果
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.jsL2g 验证明暗切换)。
13. AOS 卡片进入动画
用途: 首页瀑布流卡片加载时的进入动画
实现: 新卡片(infScroll 下拉加载)通过 IntersectionObserver 监听 .card,进入视口才加 .card-aos-enter 动画类(fade-in-up,500ms)。不作用于 .article(Masonry 绝对定位,避免重叠)。
配置: AOS 参数在 themes/matery/source/js/boot.js(duration 700ms / delay 100ms)
测试断言:下拉加载后新卡片含
.card-aos-enter,且卡片无重叠(tools/tests/infinite-scroll-aos.test.js)。
14. 悬浮面板(right-floating)
用途
右下角齿轮按钮打开的"偏好设置"面板:字体缩放、语言切换(简/繁)、显示模式(亮/自动/暗)、页面特效开关等,选择保存在 localStorage,跨页面持久化。
配置
面板为纯前端组件(layout/_partial/common/right-floating.ejs + floating-panel.styl),无独立配置开关;面板内各选项与主题既有功能联动(语言走 lang.translate、显示模式走 data-user-color-scheme、特效走 effects 开关)。
用法
- 点击右下角齿轮按钮(
.btn-floating)打开/关闭面板 - 字体缩放:A+ / A− 步进 0.1,范围 0.85–1.3,作用于根节点
--font-scaleCSS 变量;↺ 恢复默认(1.0) - 语言区:语言下拉(含国旗,行宽不足时只显国旗)+ 简/繁分段,写入本地偏好并跳转对应语言版
- 背景区:网页背景
off / 图片 / 视频(background.image/video.enable控制可选项)+ 加载动画样式 - 选择自动保存到 localStorage(如字体
matery.font-scale、背景matery.bg),刷新/跨页保持
实现效果
- 面板默认隐藏,齿轮点击展开(display flex)
- 字体缩放即时生效并跨页持久化
- 恢复默认一键还原
- 面板分区:字体 / 语言 / 显示模式 / 特效 / 背景,各区由对应总开关(
effects.enable/background.enable)控制显隐
测试断言:TC-L14(
tools/tests/floating-panel-integration.test.js,8 断言,归 release-test L11):面板默认隐藏 / 齿轮打开 / 字体缩放 / 恢复默认等。
15. 事件总线(Matery.events)
用途
主题内部组件通信的统一事件总线,解决"内容动态加载后组件需重新初始化"的问题——解密、翻页、下拉加载等场景触发对应刷新,各组件注册回调即可,无需互相耦合。
API(themes/matery/source/js/events.js)
| 方法 | 作用 |
|---|---|
Matery.events.registerRefreshCallback(cb) | 注册全量刷新回调(内容重渲染:MathJax/mermaid/Prism 等) |
Matery.events.registerLayoutCallback(cb) | 注册布局刷新回调(仅重算布局:AOS/Masonry/进度条) |
Matery.events.refresh() | 触发全部 refresh 回调 |
Matery.events.refreshLayout() | 触发全部 layout 回调(轻量,不重渲染内容) |
用法
// 内容动态加载后需要重渲染 → 全量刷新
Matery.events.registerRefreshCallback(function () { /* 重渲染 */ });
// 仅布局变化(resize/内容高度变化)→ 轻量布局刷新
Matery.events.registerLayoutCallback(function () { /* 重排 */ });
Matery.events.refreshLayout();实现效果
- refresh 与 refreshLayout 隔离:全量刷新不重复触发布局,布局刷新不重渲染内容
- 解密后统一走 refresh(见内容 tag 篇 §14 / 布局篇 §11)
测试断言:TC-L15 G3(
tools/tests/core-events-integration.test.js,4 断言):API 存在 / refresh 触发全量 / refreshLayout 触发布局 / 隔离性。
16. Banner 明暗切换
用途
Banner 背景随明暗主题切换联动:theme-changed 事件派发后,body 背景在明暗两套样式间切换;背景模式(图片/视频/关闭)由面板偏好 matery.bg 控制。
配置(主题 _config.yml)
背景偏好存 localStorage matery.bg,取值 off | image | video(互斥单选,图片/视频二选一);未设置时回落配置默认 bgDefault。图片/视频背景资源在 _config.yml 对应段配置。
实现效果
- 切换明暗主题 →
color-schema.jsdispatchtheme-changed→ banner/body 背景明暗联动 - 面板选择背景模式 → 跨页持久化(localStorage
matery.bg)
测试断言:
tools/tests/banner-bg.test.jsT5:body 背景明暗变化(theme-changed 派发)。
17. 阅读模式与代码全屏(2026-09-06 分离为两个独立功能)
用途
- 阅读模式(read_mode):文章卡片一键全屏沉浸阅读,隐藏页面其他元素
- 代码全屏(code-fullscreen):单个代码块容器全屏查看,与阅读模式相互独立(类加在代码容器而非卡片)
用法
- 阅读模式:文章信息栏(post-info)点击阅读模式按钮(
#read_mode)→ 文章卡片.card-block-fullscreen全屏;再次点击退出 - 代码全屏:代码块工具栏点击全屏按钮(
.code-area .code-fullscreen)→ 该代码容器.code-area.code-block-fullscreen全屏
实现效果
- 阅读模式进入:卡片
elastic 1s动画 + 悬浮球延迟淡入(readmode-ball-fade .3s ease .75s both——elastic transform 建立 containing block 会让 fixed 悬浮球跳动,延迟淡入解决) - 阅读模式退出:
card-block-fullscreen-exit淡出(scale .98 + opacity 0)→ 220ms 后移除全屏类(防悬浮球跳回) - 悬浮球:全屏时
position: fixed; right: 1em; top: 70px; z-index: 10000(top 70 避开导航栏 bottom 64;z 高于导航栏 997) - 代码全屏:
.code-area.code-block-fullscreen容器全屏,pre 填满 - scroll-down-bar 展开:
pre.style.maxHeight = pre.scrollHeight + 'px'(自动计算完整高度,无内部滚动条、页面滚动);收起maxHeight=''(恢复--code-max-height450px)
测试断言:
tools/tests/readmode-integration.test.js(L2f PASS=14):阅读模式进入/退出、悬浮球、代码全屏、展开后代码完整显示。
18. JS 加载分层与去 jQuery(2026-09-05 P4/P5)
用途
移除全站 jQuery 依赖(原生 DOM API 重写),并按首屏优先级分层加载脚本,降低首屏阻塞。
配置
libs.js.jquery/jqueryUI/jqueryBarrager均已注释停用(P4/P5 全站去 jQuery 完成;ripples特效原生重写,contact页删除)- 保留
jqueryPjax(独立库,非全局 jQuery) - 分层加载:核心脚本(materialize/masonry/imagesloaded/aos/events/plugins)统一
defer;统计类(umami/busuanzi)async;首屏关键内联脚本同步注入(先于所有 defer 执行)
实现效果
- 页面不再请求全局 jQuery 库
- defer 脚本不阻塞首屏解析;内联关键脚本先于 defer 执行,保证依赖顺序
测试断言:页面无全局 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,增量构建正常工作。
附:交互视觉功能速查表
| 功能 | 配置键 | 参数要点 | 自动化断言标记 |
|---|---|---|---|
| 代码块 | code | language/copy_btn/show_full | code-area |
| 灯箱 | image_zoom + libs.js.lightgallery | enable | .img-item / .lg-outer |
| 打字机 | subtitle.typed / post.typed | loop/showCursor/速度 | #typed |
| 特效 | sakura 等 10+ 开关 | 桌面+访问>2 门控 | windowWidth > BP.fun |
| 繁简 | lang.translate.enable | 聚合配置(原 zh_default/footer.translate 删除) | #translateLink |
| 进度条 | progressbar | height/color | .progress-bar |
| 回顶 | backTop | enable | #backTop |
| 打赏 | post.reward | wechat/alipay 图 | #reward |
| 打印 | print | enable | @media print |
| APlayer | music | server/type/id | aplayer |
| DPlayer | dplayer | url | dplayer |
| Bilibili | bilibili | iframeUrl | bilibili |
| ECharts | echarts | JSON 配置 | echarts |
| AOS 动画 | aos(boot.js) | duration/delay | .card-aos-enter |
| 悬浮面板 | right-floating(ejs) | 字体缩放/语言/主题/特效 | #floating-panel |
| 事件总线 | Matery.events | refresh/refreshLayout | Matery.events |
| Banner 明暗 | matery.bg(localStorage) | off/image/video | body 背景 |
| Wiki 行号 | prism line-numbers | wiki 页代码块 | .line-numbers |
| 阅读模式 | #read_mode(post-info 按钮) | 卡片全屏 + 悬浮球 | .card-block-fullscreen |
| 代码全屏 | .code-area .code-fullscreen | 容器全屏(独立于阅读模式) | .code-block-fullscreen |
| JS 加载分层 | libs.js(jquery 注释停用) | 核心 defer / 统计 async / 首屏内联同步 | 无全局 jQuery 请求 |

