模板基础概念
概述
Hugo 模板系统基于 Go 语言的 text/template
包,并对其进行了大量扩展,提供了强大而灵活的页面生成能力。理解模板的基础概念是掌握 Hugo 的关键。
模板系统架构
核心引擎
Hugo 采用 Go 的 text/template
包作为核心引擎,并在此基础上增加了:
- 丰富的内置函数库
- HTML 安全处理机制
- 模板继承系统
- 部分模板支持
模板类型
Hugo 支持多种模板类型:
- Home 模板:渲染网站首页
- Page 模板:渲染单个内容页面
- Base 模板:定义网站整体结构,供其他模板继承
变量系统
变量声明和赋值
Hugo 模板中的变量操作遵循特定语法:
{{/* 变量初始化 - 使用 := */}}
{{ $title := .Title }}
{{ $count := 0 }}
{{/* 变量赋值 - 使用 = */}}
{{ $count = add $count 1 }}
{{ $title = printf "%s - 更新版" $title }}
关键区别:
:=
用于声明并初始化新变量=
用于为已初始化的变量重新赋值
变量作用域
变量作用域是模板开发中的重要概念:
{{/* 全局作用域变量 */}}
{{ $globalVar := "全局变量" }}
{{ if .Params.featured }}
{{/* 块内作用域变量 */}}
{{ $localVar := "局部变量" }}
{{ $globalVar = "修改全局变量" }}
{{ end }}
{{/* $localVar 在此处不可访问 */}}
{{/* $globalVar 保持修改后的值 */}}
作用域规则:
- 在
if
、range
或with
块内部初始化的变量作用域仅限于该块 - 在块外部初始化的变量作用域为整个模板
- 块内可以修改外部变量的值
上下文概念(The Dot)
上下文定义
上下文(.
)是 Hugo 模板系统的核心概念,表示当前的数据环境:
{{/* 访问页面标题 */}}
<h1>{{ .Title }}</h1>
{{/* 访问站点配置 */}}
<title>{{ .Title }} - {{ .Site.Title }}</title>
{{/* 访问页面参数 */}}
{{ if .Params.description }}
<meta name="description" content="{{ .Params.description }}">
{{ end }}
上下文变化
在某些控制结构中,上下文会发生变化:
{{/* 当前上下文是页面 */}}
当前页面:{{ .Title }}
{{ with .Params.author }}
{{/* 上下文变为 .Params.author */}}
作者:{{ . }}
{{ end }}
{{ range .Site.Pages }}
{{/* 上下文变为每个页面 */}}
页面:{{ .Title }}
{{ end }}
保存上下文
当上下文发生变化时,可以保存原始上下文:
{{ $page := . }}
{{ range .Site.Pages }}
{{/* 当前上下文是迭代的页面 */}}
<a href="{{ .Permalink }}">{{ .Title }}</a>
{{/* 使用保存的页面上下文 */}}
{{ if eq . $page }}(当前页面){{ end }}
{{ end }}
控制流语句
条件语句(if/else)
{{ if .Params.featured }}
<div class="featured-post">
<h2>{{ .Title }}</h2>
</div>
{{ else if .Params.pinned }}
<div class="pinned-post">
<h2>{{ .Title }}</h2>
</div>
{{ else }}
<div class="regular-post">
<h2>{{ .Title }}</h2>
</div>
{{ end }}
循环语句(range)
{{/* 迭代页面集合 */}}
{{ range .Site.RegularPages }}
<article>
<h2><a href="{{ .Permalink }}">{{ .Title }}</a></h2>
<p>{{ .Summary }}</p>
</article>
{{ end }}
{{/* 带索引的迭代 */}}
{{ range $index, $page := .Site.RegularPages }}
<div class="post-{{ $index }}">
<h3>{{ $page.Title }}</h3>
</div>
{{ end }}
{{/* 迭代映射 */}}
{{ range $key, $value := .Params.tags }}
<span class="tag">{{ $key }}: {{ $value }}</span>
{{ end }}
with 语句
{{ with .Params.author }}
<div class="author-info">
<h3>作者信息</h3>
<p>{{ . }}</p>
</div>
{{ end }}
{{/* with...else 结构 */}}
{{ with .Params.description }}
<meta name="description" content="{{ . }}">
{{ else }}
<meta name="description" content="{{ .Site.Params.description }}">
{{ end }}
高级控制语句
Hugo 还提供了更多高级控制语句:
{{/* block 语句 - 用于模板继承 */}}
{{ block "content" . }}
<p>默认内容</p>
{{ end }}
{{/* break 和 continue */}}
{{ range .Site.Pages }}
{{ if gt .Date.Year 2020 }}
{{ continue }}
{{ end }}
{{ if eq .Title "特殊页面" }}
{{ break }}
{{ end }}
<p>{{ .Title }}</p>
{{ end }}
{{/* return 语句 - 在部分模板中使用 */}}
{{ if not .Title }}
{{ return }}
{{ end }}
<h1>{{ .Title }}</h1>
{{/* try 语句 - 错误处理 */}}
{{ $result := try (.Params.invalidField | default "默认值") }}
{{ if $result.IsError }}
<p>处理出错:{{ $result.Error }}</p>
{{ else }}
<p>结果:{{ $result.Value }}</p>
{{ end }}
数据访问
访问切片和映射
{{/* 使用 index 函数访问 */}}
{{ $firstTag := index .Params.tags 0 }}
{{ $author := index .Params "author" }}
{{/* 安全访问不存在的索引 */}}
{{ with index .Params.tags 5 }}
第六个标签:{{ . }}
{{ else }}
标签不足六个
{{ end }}
零索引系统
Hugo 使用零索引系统:
{{ $tags := slice "技术" "教程" "Hugo" }}
第一个标签:{{ index $tags 0 }} {{/* 输出:技术 */}}
第二个标签:{{ index $tags 1 }} {{/* 输出:教程 */}}
第三个标签:{{ index $tags 2 }} {{/* 输出:Hugo */}}
部分模板
基本概念
部分模板是存储在 layouts/_partials
目录下的可重用模板片段:
layouts/ └── _partials/ ├── header.html ├── footer.html └── post-summary.html
使用部分模板
{{/* 包含部分模板 */}}
{{ partial "header.html" . }}
{{/* 传递自定义数据 */}}
{{ partial "post-summary.html" (dict "page" . "showDate" true) }}
{{/* 缓存部分模板 */}}
{{ partialCached "footer.html" . }}
创建部分模板
layouts/_partials/post-summary.html
:
<article class="post-summary">
<h2><a href="{{ .page.Permalink }}">{{ .page.Title }}</a></h2>
{{ if .showDate }}
<time>{{ .page.Date.Format "2006-01-02" }}</time>
{{ end }}
<p>{{ .page.Summary }}</p>
</article>
最佳实践
变量命名
{{/* 推荐:使用描述性变量名 */}}
{{ $currentPage := . }}
{{ $totalPosts := len .Site.RegularPages }}
{{ $isHomePage := .IsHome }}
{{/* 避免:使用模糊的变量名 */}}
{{ $p := . }}
{{ $n := len .Site.RegularPages }}
{{ $flag := .IsHome }}
上下文管理
{{/* 在复杂嵌套中保存重要上下文 */}}
{{ $site := .Site }}
{{ $page := . }}
{{ range .Site.Menus.main }}
{{ range .Children }}
{{/* 可以安全访问原始上下文 */}}
{{ if eq .URL $page.RelPermalink }}
<a class="active" href="{{ .URL }}">{{ .Name }}</a>
{{ else }}
<a href="{{ .URL }}">{{ .Name }}</a>
{{ end }}
{{ end }}
{{ end }}
错误处理
{{/* 使用 with 语句进行安全访问 */}}
{{ with .Params.customField }}
<div class="custom-content">{{ . }}</div>
{{ end }}
{{/* 使用 try 语句处理复杂错误 */}}
{{ $imageResult := try (resources.Get .Params.image) }}
{{ if $imageResult.IsError }}
<p>图片加载失败</p>
{{ else }}
<img src="{{ $imageResult.Value.RelPermalink }}" alt="{{ .Title }}">
{{ end }}
小结
Hugo 模板系统的基础概念是构建高质量网站的基石。通过本章的学习,你应该已经掌握了:
核心概念回顾
- 模板系统架构:基于 Go 的
text/template
包,扩展了丰富的功能 - 变量系统:理解
:=
初始化和=
赋值的区别,掌握作用域规则 - 上下文管理:熟练使用
.
和$
访问不同层级的数据 - 控制流语句:掌握条件判断、循环迭代和上下文切换
- 数据访问:安全地访问切片、映射和对象属性
- 部分模板:实现代码复用和模块化设计
关键要点
- 上下文是核心:始终关注当前上下文的变化,这是避免模板错误的关键
- 防御性编程:使用
with
、try
等语句处理可能的空值和错误 - 性能优化:合理缓存数据查询结果,避免重复计算
- 代码可读性:使用描述性变量名,保持模板逻辑清晰
下一步学习
掌握了这些基础概念后,你可以继续深入学习:
通过系统地学习和实践,你将能够创建出功能强大、性能优异且易于维护的 Hugo 模板。