Scriban 语法速查

3m45s

引言

Scriban是一个功能强大、语法简洁的模板引擎,被TMaker采用作为页面渲染的核心。它采用类似Liquid的语法,支持变量输出、条件判断、循环渲染、函数调用等丰富特性,同时具备优秀的性能和安全性。掌握Scriban的基本语法是高效使用TMaker的前提。

本文是Scriban语法的快速参考指南,涵盖了模板开发中最常用的语法结构、内置函数、过滤器使用、以及实战技巧。无论你是刚接触Scriban的新手,还是需要查阅语法细节的熟练开发者,这份参考都能帮你快速找到所需信息。建议配合VS Code的Scriban语法高亮扩展使用,必要时也可以借助Claude Code、OpenAI Codex或GLM等AI工具进行语法校对和代码生成。

变量与输出

在TMaker中,所有页面数据都存储在post对象中。通过post.xxx访问字段数据,使用双花括号{{ }}输出变量值。

基础输出

{{ post.title }}
          {{ post.summary }}
          {{ post.author.name }}
          {{ post.publishDate }}

安全访问(避免null错误)

<!-- 使用默认值 -->
          {{ post.description | default: "暂无描述" }}
          
          <!-- 条件输出 -->
          {{ if post.subtitle }}
            <p class="subtitle">{{ post.subtitle }}</p>
          {{ end }}
          
          <!-- 安全导航操作符(可选链) -->
          {{ post.author?.name | default: "匿名" }}

变量赋值

{{ $pageTitle = post.title + " | TMaker文档" }}
          {{ $currentYear = date.now | date.year }}
          
          <title>{{ $pageTitle }}</title>
          <footer>© {{ $currentYear }} TMaker</footer>

对象和数组访问

<!-- 对象字段访问 -->
          {{ post.author.name }}
          {{ post["author"]["name"] }}  <!-- 方括号访问 -->
          
          <!-- 数组索引访问 -->
          {{ post.tags[0] }}
          {{ post.relatedPosts[1].title }}

条件判断

Scriban提供丰富的条件判断语法,支持ifelse ifelse以及多种比较运算符。

基本条件

{{ if post.isFeatured }}
            <div class="badge">精选文章</div>
          {{ end }}
          
          <!-- if-else -->
          {{ if post.coverImage }}
            <img src="{{ post.coverImage }}" alt="{{ post.title }}" />
          {{ else }}
            <img src="/images/default-cover.jpg" alt="默认封面" />
          {{ end }}

多分支条件

{{ if post.status == "draft" }}
            <span class="badge badge-gray">草稿</span>
          {{ else if post.status == "published" }}
            <span class="badge badge-green">已发布</span>
          {{ else if post.status == "archived" }}
            <span class="badge badge-red">已归档</span>
          {{ else }}
            <span class="badge">未知状态</span>
          {{ end }}

比较运算符

<!-- 等于/不等于 -->
          {{ if post.category == "tech" }}
          {{ if post.category != "draft" }}
          
          <!-- 大小比较 -->
          {{ if post.readTime > 10 }}
          {{ if post.viewCount >= 1000 }}
          {{ if post.rating < 3.5 }}
          {{ if post.priority <= 5 }}
          
          <!-- 逻辑运算 -->
          {{ if post.isPublished && post.isFeatured }}
          {{ if post.isDraft || post.isPending }}
          {{ if !post.isHidden }}
          
          <!-- 存在性检查 -->
          {{ if post.tags }}  <!-- 检查是否存在且非空 -->
          {{ if post.description == null }}  <!-- 检查是否为null -->

三元运算符

{{ $statusClass = post.isPublished ? "published" : "draft" }}
          <div class="status-{{ $statusClass }}">{{ post.title }}</div>

循环渲染

使用for循环遍历数组和对象,Scriban提供了丰富的循环辅助变量。

基础循环

{{ for item in post.toc }}
            <a href="#{{ item.id }}">{{ item.title }}</a>
          {{ end }}
          
          <!-- 遍历标签 -->
          {{ for tag in post.tags }}
            <span class="tag">{{ tag }}</span>
          {{ end }}

循环辅助变量

{{ for article in post.relatedPosts }}
            <div class="article
              {{ if for.first }} first{{ end }}
              {{ if for.last }} last{{ end }}
              {{ if for.even }} even{{ else }} odd{{ end }}
            ">
              <h3>{{ for.index }}. {{ article.title }}</h3>
              <p>共 {{ for.length }} 篇相关文章,当前第 {{ for.index }} 篇</p>
            </div>
          {{ end }}
          
          <!-- 循环辅助变量说明:
            for.index    - 当前索引(从1开始)
            for.rindex   - 反向索引(从长度到1)
            for.first    - 是否第一项
            for.last     - 是否最后一项
            for.even     - 是否偶数项
            for.odd      - 是否奇数项
            for.length   - 总长度
          -->

带条件的循环

<!-- 过滤条件 -->
          {{ for post in posts }}
            {{ if post.isPublished }}
              <article>{{ post.title }}</article>
            {{ end }}
          {{ end }}
          
          <!-- 或使用数组过滤器 -->
          {{ for post in posts | array.filter "isPublished" }}
            <article>{{ post.title }}</article>
          {{ end }}

循环范围

<!-- 数字范围循环 -->
          {{ for i in 1..5 }}
            <div class="item-{{ i }}">Item {{ i }}</div>
          {{ end }}
          
          <!-- 限制循环次数 -->
          {{ for post in posts | array.limit 3 }}
            <div>{{ post.title }}</div>
          {{ end }}

循环中断

{{ for item in items }}
            {{ if item.id == targetId }}
              <div>找到了:{{ item.name }}</div>
              {{ break }}  <!-- 跳出循环 -->
            {{ end }}
          {{ end }}
          
          {{ for item in items }}
            {{ if item.isHidden }}
              {{ continue }}  <!-- 跳过当前项 -->
            {{ end }}
            <div>{{ item.name }}</div>
          {{ end }}

组件引入

使用include引入自定义组件,实现代码复用和模块化。

基础引入

<!-- 引入组件(文件名不含.sbn扩展名) -->
          {{ include 'docsSidebar' }}
          {{ include 'ui/button' }}
          {{ include 'content/article-card' }}

传递参数

<!-- 传递参数对象 -->
          {{ include 'ui/button' with {
            text: '查看更多',
            type: 'primary',
            link: '/blog/',
            size: 'large'
          } }}
          
          <!-- 组件内部通过$0访问参数 -->
          <!-- components/ui/button.sbn -->
          <a href="{{ $0.link }}" class="btn btn-{{ $0.type }} btn-{{ $0.size }}">
            {{ $0.text }}
          </a>

传递当前数据

<!-- 传递整个post对象 -->
          {{ include 'content/article-card' with post }}
          
          <!-- 传递子对象 -->
          {{ include 'ui/user-avatar' with post.author }}
          
          <!-- 传递数组项 -->
          {{ for article in post.relatedPosts }}
            {{ include 'content/article-card' with article }}
          {{ end }}

内置过滤器

Scriban提供丰富的内置过滤器(管道函数),用于数据转换和格式化。

字符串处理

<!-- 大小写转换 -->
          {{ post.title | upcase }}           <!-- 全大写 -->
          {{ post.title | downcase }}         <!-- 全小写 -->
          {{ post.title | capitalize }}       <!-- 首字母大写 -->
          
          <!-- 字符串操作 -->
          {{ post.summary | truncate: 100 }}  <!-- 截断到100字符 -->
          {{ post.content | strip_html }}     <!-- 移除HTML标签 -->
          {{ post.slug | replace: "-", "_" }} <!-- 替换字符 -->
          {{ post.title | append: " - TMaker" }}  <!-- 追加字符串 -->
          {{ "Hello" | prepend: "Say: " }}    <!-- 前置字符串 -->
          
          <!-- 修剪空白 -->
          {{ post.content | strip }}          <!-- 去除首尾空白 -->
          {{ post.content | lstrip }}         <!-- 去除左侧空白 -->
          {{ post.content | rstrip }}         <!-- 去除右侧空白 -->

数字处理

<!-- 数学运算 -->
          {{ post.price | times: 0.8 }}       <!-- 乘法 -->
          {{ post.count | plus: 10 }}         <!-- 加法 -->
          {{ post.total | minus: 5 }}         <!-- 减法 -->
          {{ post.amount | divided_by: 2 }}   <!-- 除法 -->
          {{ post.value | modulo: 3 }}        <!-- 取模 -->
          
          <!-- 数字格式化 -->
          {{ post.price | math.round }}       <!-- 四舍五入 -->
          {{ post.price | math.ceil }}        <!-- 向上取整 -->
          {{ post.price | math.floor }}       <!-- 向下取整 -->
          {{ post.rating | math.format "0.00" }}  <!-- 格式化为两位小数 -->

数组处理

<!-- 数组操作 -->
          {{ post.tags | array.size }}        <!-- 获取长度 -->
          {{ post.tags | array.first }}       <!-- 第一个元素 -->
          {{ post.tags | array.last }}        <!-- 最后一个元素 -->
          {{ post.tags | array.join: ", " }}  <!-- 连接为字符串 -->
          {{ post.tags | array.sort }}        <!-- 排序 -->
          {{ post.tags | array.uniq }}        <!-- 去重 -->
          {{ post.tags | array.reverse }}     <!-- 反转 -->
          {{ posts | array.limit: 5 }}        <!-- 限制数量 -->
          {{ posts | array.offset: 3 }}       <!-- 跳过前3个 -->
          
          <!-- 过滤 -->
          {{ posts | array.filter "isPublished" }}  <!-- 过滤 -->
          {{ posts | array.where "category", "tech" }}  <!-- 条件过滤 -->

日期处理

<!-- 日期格式化 -->
          {{ post.publishDate | date.format "%Y-%m-%d" }}     <!-- 2026-02-11 -->
          {{ post.publishDate | date.format "%Y年%m月%d日" }}  <!-- 2026年02月11日 -->
          {{ post.publishDate | date.format "%B %d, %Y" }}   <!-- February 11, 2026 -->
          
          <!-- 相对时间 -->
          {{ post.publishDate | date.to_string }}     <!-- 格式化为字符串 -->
          {{ date.now }}                              <!-- 当前时间 -->
          {{ date.now | date.year }}                  <!-- 当前年份 -->

URL和HTML处理

<!-- URL编码 -->
          {{ post.title | url_encode }}       <!-- URL编码 -->
          {{ post.content | escape }}         <!-- HTML转义 -->
          {{ post.safeHtml | raw }}           <!-- 原始输出(不转义) -->

内置函数

除了过滤器,Scriban还提供了一些内置函数用于更复杂的操作。

字符串函数

<!-- 字符串包含检查 -->
          {{ if string.contains post.title "TMaker" }}
            <span>这是关于TMaker的文章</span>
          {{ end }}
          
          <!-- 字符串开始/结束检查 -->
          {{ if string.starts_with post.url "/blog/" }}
          {{ if string.ends_with post.filename ".md" }}
          
          <!-- 字符串分割 -->
          {{ $parts = string.split post.tags_string "," }}
          {{ for part in $parts }}
            <span>{{ part | strip }}</span>
          {{ end }}

数组函数

<!-- 数组包含检查 -->
          {{ if array.contains post.tags "TMaker" }}
            <span>标签包含TMaker</span>
          {{ end }}
          
          <!-- 数组映射 -->
          {{ $names = array.map posts "title" }}  <!-- 提取所有title字段 -->

高级特性

自定义函数

<!-- 定义函数 -->
          {{ func format_author(author)
            ret author.name + " <" + author.email + ">"
          end }}
          
          <!-- 使用函数 -->
          {{ format_author post.author }}

捕获输出

<!-- 捕获内容到变量 -->
          {{ capture $authorInfo }}
            <div class="author">
              <h3>{{ post.author.name }}</h3>
              <p>{{ post.author.bio }}</p>
            </div>
          {{ end }}
          
          <!-- 稍后使用捕获的内容 -->
          {{ $authorInfo }}

注释

<!-- Scriban注释(不会输出到HTML) -->
          {{## 这是单行注释 ##}}
          
          {{##
            这是多行注释
            可以写很多行
          ##}}

常见陷阱与最佳实践

1. 不要在.sbn中包含完整HTML结构

<!-- ✗ 错误:包含html/head/body标签 -->
          <html>
          <head><title>{{ post.title }}</title></head>
          <body>
            <h1>{{ post.title }}</h1>
          </body>
          </html>
          
          <!-- ✓ 正确:只写内容部分 -->
          <h1>{{ post.title }}</h1>
          <p>{{ post.summary }}</p>

2. Clean URL规范

<!-- ✓ 正确:以/结尾 -->
          <a href="/docs/config/">配置说明</a>
          <a href="/blog/{{ post.slug }}/">{{ post.title }}</a>
          
          <!-- ✗ 错误:不带/或带.html -->
          <a href="/docs/config">配置说明</a>
          <a href="/blog/{{ post.slug }}.html">{{ post.title }}</a>

3. 数据字段命名

// ✓ 正确:使用小驼峰命名
          {
            "publishDate": "2026-02-11",
            "authorName": "张三",
            "isPublished": true
          }
          
          // ✗ 错误:不规范的命名
          {
            "publish_date": "2026-02-11",
            "AuthorName": "张三",
            "published": true
          }

4. 避免过度嵌套

<!-- ✗ 不推荐:深层嵌套 -->
          {{ if post.author }}
            {{ if post.author.profile }}
              {{ if post.author.profile.avatar }}
                <img src="{{ post.author.profile.avatar }}" />
              {{ end }}
            {{ end }}
          {{ end }}
          
          <!-- ✓ 推荐:使用默认值或安全导航 -->
          {{ $avatar = post.author?.profile?.avatar | default: "/images/default-avatar.jpg" }}
          <img src="{{ $avatar }}" />

5. 组件参数传递

<!-- ✓ 正确:明确传递需要的数据 -->
          {{ include 'ui/card' with {
            title: post.title,
            summary: post.summary,
            image: post.coverImage
          } }}
          
          <!-- ✗ 不推荐:传递整个post可能包含不必要的数据 -->
          {{ include 'ui/card' with post }}

6. 使用AI辅助

在VS Code中编写Scriban模板时,建议安装Scriban Language扩展获得语法高亮。遇到复杂的模板逻辑时,可以借助AI工具:

  • Claude Code:擅长理解复杂的数据结构和模板逻辑,适合重构和优化
  • OpenAI Codex:擅长生成Scriban代码片段和过滤器链
  • GLM(智谱清言):擅长中文注释和文档生成

调试技巧

输出调试信息

<!-- 输出完整对象结构(JSON格式) -->
          <pre>{{ post | json }}</pre>
          
          <!-- 输出对象类型 -->
          {{ post.tags | object.typeof }}
          
          <!-- 条件断点 -->
          {{ if post.id == "debug-target" }}
            <pre>Debug: {{ post | json }}</pre>
          {{ end }}

常见错误排查

  • 语法错误:检查{{}}是否配对,end关键字是否遗漏
  • 变量未定义:确认.data.json中字段存在且拼写正确
  • 循环不执行:检查数组是否为空或null
  • 组件找不到:确认组件文件存在且路径正确

学习资源

  • 官方文档Scriban GitHub
  • 在线测试:Scriban Playground(在线尝试语法)
  • VS Code扩展:Scriban Language(语法高亮和智能提示)
  • TMaker示例:查看templates/tmaker/下的示例模板

总结

Scriban是一个功能强大且易于学习的模板引擎。掌握变量输出、条件判断、循环渲染、组件引入这四大核心特性,就能完成大部分模板开发工作。配合丰富的内置过滤器和函数,可以实现复杂的数据处理和格式化。遵循Clean URL规范、合理命名数据字段、避免过度嵌套,能够编写出清晰、可维护的模板代码。

在实际开发中,善用VS Code的语法高亮扩展,遇到复杂逻辑时借助AI工具辅助,能够显著提升开发效率。记住,模板引擎只是工具,关键在于理解数据流和组件化思想。通过持续实践和参考优秀示例,你会越来越熟练地使用Scriban构建高质量的模板。

找不到你需要的内容?

联系我们