hexo 学习 0027:hexo 模板

模板是 Hexo 主题的灵魂,它决定了网站内容最终如何呈现给访客。你可以把模板想象成建筑蓝图:layout 是整体框架,partials 是预制的门窗组件,而具体的页面模板(如 index, post)则是不同房间的具体装修方案。

核心模板类型与回退机制

Hexo 根据不同的页面类型自动调用对应的模板文件。如果你的主题中缺少某个特定模板,Hexo 会按照“回退”(Fallback)机制寻找替代者,确保页面不会空白。

模板名称 对应页面 回退机制 (若缺失则使用)
index 首页 无 (每个主题必须包含此模板)
post 文章详情页 index
page 独立分页 (如关于我) index
archive 归档页 (按时间列表) index
category 分类归档页 archive
tag 标签归档页 archive

概念辨析:回退机制
回退机制就像是一个“备用计划”。例如,当你访问某篇文章时,Hexo 首先寻找 post.ejs (或 .njk)。如果主题开发者没有创建这个文件,Hexo 不会报错,而是自动转而使用 index.ejs 来渲染文章内容。同理,如果没有专门的分类页模板,它会尝试使用归档页模板。这种设计降低了主题开发的门槛,允许开发者复用代码,但也要求开发者明确知道哪些页面共用了模板,以免样式错乱。

布局 (Layout):共享骨架

当多个页面拥有相同的结构(例如都有相同的页眉 Header 和页脚 Footer)时,重复编写这些代码是低效且难以维护的。布局(Layout)功能允许你定义一个通用的外壳,具体的页面内容只需填充到中间即可。

核心规则:
布局文件中必须包含 <%- body %> 变量。这个变量就像一个“插槽”,具体模板生成的内容会被注入到这里。默认情况下,所有模板都会使用 layout 布局。

配置示例:

假设我们有一个布局文件 layout.ejs

1
2
3
4
5
6
7
8
9
10
11
<!doctype html>
<html>
<head>
<title>My Blog</title>
</head>
<body>
<header>Site Header</header>
<%- body %>
<footer>Site Footer</footer>
</body>
</html>

以及一个首页模板 index.ejs

1
2
<h1>Welcome to Home</h1>
<p>This is the main content.</p>

生成结果:
Hexo 会将 index.ejs 的内容替换掉 layout.ejs 中的 <%- body %>,最终输出:

1
2
3
4
5
6
7
8
9
10
11
12
<!doctype html>
<html>
<head>
<title>My Blog</title>
</head>
<body>
<header>Site Header</header>
<h1>Welcome to Home</h1>
<p>This is the main content.</p>
<footer>Site Footer</footer>
</body>
</html>

高级用法:

  1. 指定其他布局:在模板的 Front-matter 中设置 layout: 自定义布局名,可以使用非默认的布局文件。
  2. 关闭布局:在 Front-matter 中设置 layout: false,该模板将直接输出,不包裹任何布局外壳。这常用于生成 sitemap.xml 或 rss.xml 等纯数据文件。
  3. 嵌套布局:布局文件本身也可以使用另一个布局,形成多层嵌套结构,适合复杂的大型站点。

Partials:组件化开发

Partials(局部模板)是将页面拆分为小组件的关键工具。典型的例子包括页眉、页脚、侧边栏、文章卡片等。将这部分代码提取为单独的文件,可以极大提高代码的可维护性和复用性。

基本用法:
使用 <%- partial('路径/文件名') %> 语法引入局部模板。

示例:
文件 partial/header.ejs

1
<h1 id="logo"><%= config.title %></h1>

文件 index.ejs

1
2
<%- partial('partial/header') %>
<div id="content">Home page content</div>

生成结果:

1
2
<h1 id="logo">My Site</h1>
<div id="content">Home page content</div>

局部变量传递

默认情况下,Partial 继承父模板的所有变量。但你也可以显式地传递特定的局部变量,这在需要动态修改组件内容时非常有用。

参数示例:

1
2
<!-- 在 index.ejs 中调用 -->
<%- partial('partial/header', {title: 'Hello World'}) %>

对应的 partial/header.ejs

1
<h1 id="logo"><%= title %></h1>

作用说明:
这里我们向 header 局部传递了一个名为 title 的变量,值为 'Hello World'。在局部文件内部,title 变量会被覆盖为传入的值,而不是全局配置中的站点标题。这就像是在组装家具时,虽然大部分螺丝是通用的,但你可以特意指定某几个位置使用特殊颜色的螺丝。

性能优化:局部缓存 (Fragment Caching)

随着主题变得复杂或文章数量增加,每次生成站点都重新渲染所有 Partial 会导致速度变慢。Hexo 提供了局部缓存功能,灵感来源于 Ruby on Rails。

原理:
Hexo 会存储 Partial 第一次渲染后的 HTML 结果。在后续生成其他页面时,如果再次用到相同的 Partial,直接输出缓存内容,跳过渲染过程。这能显著减少文件查询和模板编译的时间。

使用方法:

方法一:使用 fragment_cache 函数

1
2
3
<%- fragment_cache('header', function(){
return '<header>...</header>'; // 这里可以是复杂的渲染逻辑
});

方法二:在 partial 中开启缓存选项(推荐)

1
<%- partial('header', {}, {cache: true});

参数说明:

  • cache: true:告诉 Hexo 对该 Partial 启用缓存。

重要注意事项与概念辨析:

  1. 适用场景:只有当 Partial 在所有页面中渲染结果完全一致时,才能开启缓存。例如全站统一的页脚、固定的侧边栏菜单。
  2. 禁用场景:如果 Partial 的内容依赖于当前页面的上下文(例如“上一篇/下一篇”链接、面包屑导航、相对链接),绝对不能开启缓存。
    • 案例:如果你在全局配置中启用了 relative_link: true,那么每个页面的相对路径都是不同的。如果在 header 中使用了缓存,第一个页面生成的相对路径会被缓存,后续所有页面都会错误地显示相同的路径,导致链接失效。
    • 比喻:缓存就像是打印好的传单。如果传单内容是“欢迎来到本站”(全站通用),你可以一次打印一万份分发。但如果传单内容是“您现在的位置是 X”(随页面变化),你就不能预先打印,必须到了现场根据位置手写,否则所有人拿到的地点信息都是错的。

通过合理使用模板、布局、Partials 以及局部缓存,你可以构建出既结构清晰、易于维护,又具备高性能生成的 Hexo 主题。