写模板经常遇到两种麻烦:一是「盲人摸象」,不知道当前页面到底有哪些变量可以调;二是缺少必要的页面函数,辛辛苦苦把 Markdown 编译成了 HTML,页面上一看却把 <h1>、<p> 标签当纯文本原样打印了出来——排查半天,才发现是缺少 safe 之类的过滤器。
RustPress 选用 Tera 作为模板渲染引擎。Tera 深度借鉴了 Python 社区的 Jinja2 和 Django 模板哲学,语法直观优雅,同时在 Rust 编译器底层完成了极致的速度优化。
本篇系统梳理 Tera 的核心语法、常用过滤器,以及 RustPress 运行时自动注入的全量上下文变量清单。
一、Tera 核心语法
1. 变量输出与安全转义
<!-- 普通变量:默认会自动进行 HTML 转义,防止 XSS -->
<h1>{{ page.title }}</h1>
<!-- 输出编译后的 HTML 正文:必须加 | safe 过滤器,否则标签会被转义为纯源码 -->
<div class="prose">
{{ page.content | safe }}
</div>
2. 条件分支(if / elif / else)
{% if page.draft %}
<span class="badge-draft">草稿</span>
{% elif page.is_pinned %}
<span class="badge-pinned">置顶</span>
{% else %}
<span class="badge-normal">普通</span>
{% endif %}
3. 循环遍历(for ... in)
<ul>
{% for tag in page.tags %}
<li><a href="/tag/{{ tag }}/"># {{ tag }}</a></li>
{% empty %}
<li>暂无标签</li>
{% endfor %}
</ul>
在 for 循环内部,Tera 自动提供了实用的循环状态变量:
loop.index:从 1 开始的计数;loop.index0:从 0 开始的索引;loop.first:布尔值,是否为第一项;loop.last:布尔值,是否为最后一项。
4. 模板继承与插槽(extends & block)
<!-- 子模板 post.html -->
{% extends "base.html" %}
{% block title %}{{ page.title }} - {{ site.name }}{% endblock title %}
{% block content %}
<main class="container mx-auto px-4 py-8">
<article>
<h1>{{ page.title }}</h1>
<div class="content">{{ page.content | safe }}</div>
</article>
</main>
{% endblock content %}
二、常用过滤器(Filters)速查清单
safe(安全 HTML 标记)- 语法示例:
{{ page.content | safe }} - 说明效果:标记为可信的富文本 HTML,禁用默认转义,直接渲染 HTML 标签。
- 语法示例:
default(缺省默认值兜底)- 语法示例:
{{ site.author.maxim | default(value="博学审问") }} - 说明效果:当目标变量为 null、undefined 或空时,采用指定的兜底默认值。
- 语法示例:
truncate(字符串截断)- 语法示例:
{{ post.description | truncate(length=80) }} - 说明效果:截取前 80 个字符并在末尾自动拼接省略号
...。
- 语法示例:
slice(数组切片截取)- 语法示例:
{% for p in posts | slice(end=5) %} - 说明效果:截取数组的前 5 个元素进行遍历。
- 语法示例:
length(长度/计数统计)- 语法示例:
{{ page.tags | length }} - 说明效果:计算并返回数组元素个数或字符串字符总数。
- 语法示例:
lower/upper(大小写转换)- 语法示例:
{{ post.slug | lower }} - 说明效果:将文本统一转换为全小写或全大写。
- 语法示例:
first/last(首尾元素提取)- 语法示例:
{{ page.tags | first }} - 说明效果:快速提取数组的第一项(首元素)或最后一项(末元素)。
- 语法示例:
三、RustPress 全局上下文变量大盘点
在渲染每个页面时,RustPress 会把以下数据自动注入 Tera 上下文:
1. site 对象(全站全局配置)
site.name:网站名称(如"艺述论")site.description:网站描述与 Slogansite.domain:正式线上域名(如"https://yishulun.com")site.base_url:当前环境基准 URLsite.author.name:作者姓名site.author.bio:作者一句话简介site.author.maxim:作者座右铭site.author.avatar:作者头像路径site.author.email:联系邮箱site.author.donate_qrcode:赞赏码图片路径site.social:包含github,twitter,youtube,zhihu,bilibili,rss等各平台链接字典site.icp_license:备案号site.start_year:创站年份
2. page 对象(当前渲染页面的元数据)
page.title:文章或专栏标题page.content:Markdown 编译后的 HTML 正文page.date_ymd:发布日期(YYYY-MM-DD)page.create_time_hm:发布时间(HH:MM)page.tags:标签列表数组page.categories:分类层级列表数组page.draft:布尔值,是否为草稿page.url:当前页面的相对访问路径(如"/2026/01.html")page.description:文章摘要page.cover:封面图片路径page.comments:布尔值,是否开启评论区
3. 数据集合对象
posts/all_posts:文章对象列表;columns:全站专栏元数据数组;features:全局功能开关(features.search,features.comments,features.analytics等);analytics.google_id:GA4 衡量 ID。
Tera 模板引擎提供了强大的逻辑控制与过滤器支持,赋予了前端极大的布局自由度;但如果在 HTML 模板中强行编写深度嵌套的多层计算或复杂字符串清洗,会破坏模板的可读性与渲染性能。模板层仅负责「如何将已有数据渲染为 HTML」;所有复杂的数据清洗、排序算法与倒分页计算等,均在 Rust 语言里面预先算好,并直接注入上下文。模板引擎只负责视图排版,数据计算则交给专业的后端语言。
下一篇,我们来看如何从零手搓一套属于自己的专属主题。