模板入门介绍
template(模板)是包?template actions(模板动作)的文件,位于项目、主题或模块?layouts 目录内
模板使用 变量、函数 和 方法 将您的内容、资源和数据转换为已发布的页面。
Hugo 使用 Go 的 text/template 和 html/template 包。
text/template 包实现数据驱动的模板以生成文本输出,而 html/template 包实现数据驱动的模板以生成 HTML 输出,防止代码注入。
默认情况下,Hugo 在渲染 HTML 文件时使用 html/template 包。
例如,此 HTML 模板初始化 $v1 和 $v2 变量,然后在 HTML 段落中显示它们及其乘积。
{{ $v1 := 6 }}
{{ $v2 := 7 }}
<p>{{ $v1 }} 和 {{ $v2 }} 的乘积是 {{ mul $v1 $v2 }}。</p>虽然 HTML 模板最常见,但您可以为任何 输出格式 创建模板,包括 CSV、JSON、RSS 和纯文本。
上下文
在创建模板之前,需要理解的最重要概念是 上下文,即传递给每个模板的数据。数据可以是一个简单的值,或者更常见的是 对象 及其关联的 方法。
例如,页面 模板接收一个 Page 对象,Page 对象提供方法来返回值或执行操作。
当前上下文
在模板中,点 (.) 表示当前上下文。
<h2>{{ .Title }}</h2>在上面的示例中,点表示 Page 对象,我们调用其 Title 方法来返回 前言 中定义的标题。
当前上下文可能在模板中发生变化。例如,在模板的顶部,上下文可能是 Page 对象,但我们在 range 或 with 块中将上下文重新绑定为其他值或对象。
<h2>{{ .Title }}</h2>
{{ range slice "foo" "bar" }}
<p>{{ . }}</p>
{{ end }}
{{ with "baz" }}
<p>{{ . }}</p>
{{ end }}在上面的示例中,当我们 遍历 切片 值时,上下文会发生变化。在第一次迭代中,上下文是 “foo”,在第二次迭代中,上下文是 “bar”。在 with 块内,上下文是 “baz”。Hugo 将上述内容渲染为:
<h2>我的页面标题</h2>
<p>foo</p>
<p>bar</p>
<p>baz</p>模板上下文
在 range 或 with 块中,您可以通过在点前添加美元符号 ($) 来访问传递给模板的上下文:
{{ with "foo" }}
<p>{{ $.Title }} - {{ . }}</p>
{{ end }}Hugo 将此渲染为:
<p>我的页面标题 - foo</p>在继续阅读之前,请确保您彻底理解 上下文 的概念。新手用户最常见的模板错误与上下文有关。
动作
在上面的示例中,成对的开始和结束大括号表示模板动作的开始和结束,模板动作是模板内的数据评估或控制结构。
模板动作可以包含字面值(布尔值、字符串、整数 和 浮点数)、当前上下文、变量、函数、方法 和 nil 关键字。
{{ $convertToLower := true }}
{{ if $convertToLower }}
<h2>{{ strings.ToLower .Title }}</h2>
{{ end }}在上面的示例中:
$convertToLower是一个变量true是一个字面布尔值if是控制结构的开始strings.ToLower是一个将所有字符转换为小写的函数Title是Page对象上的一个方法end是控制结构的结束
Hugo 将上述内容渲染为:
<h2>我的页面标题</h2>
空白
注意到上一个示例中的空行和缩进了吗?虽然在生产环境中通常会对输出进行压缩,因此这些空白无关紧要,但您可以使用带连字符的模板动作分隔符来删除相邻的空白:
{{- $convertToLower := true -}}
{{- if $convertToLower -}}
<h2>{{ strings.ToLower .Title }}</h2>
{{- end -}}Hugo 将此渲染为:
<h2>我的页面标题</h2>空白包括空格、水平制表符、回车符和换行符。
引号字符
Hugo 模板使用不同的引号字符来定义文本和字符的处理方式。
使用双引号表示 解释型字符串字面值。这些将反斜杠解释为特殊指令:
{{ print "Hello world\u0021" }} → Hello world!使用反引号表示 原始字符串字面值。这些忽略反斜杠并按字面处理每个字符:
{{ print `Hello world\u0021` }} → Hello world\u0021使用单引号表示 rune 字面值。与字符串不同,这些将单个字符表示为其数字 Unicode 值:
{{ print '!' }} → 33实际上,您几乎不会在模板代码中使用 rune 字面值。它们最常用于低级编程;在 Hugo 模板中,您几乎总是需要字符串。
管道
在模板动作中,您可以将值 管道 传递给函数或方法。管道值成为函数或方法的最后一个参数。例如,这些是等价的:
{{ strings.ToLower "Hugo" }} → hugo
{{ "Hugo" | strings.ToLower }} → hugo您可以将一个函数或方法的结果管道传递给另一个。例如,这些是等价的:
{{ strings.TrimSuffix "o" (strings.ToLower "Hugo") }} → hug
{{ "Hugo" | strings.ToLower | strings.TrimSuffix "o" }} → hug这些也是等价的:
{{ mul 6 (add 2 5) }} → 42
{{ 5 | add 2 | mul 6 }} → 42请记住,管道值成为您管道传递到的函数或方法的最后一个参数。
行分割
您可以将模板动作分割到两行或多行。例如,这些是等价的:
{{ $v := or $arg1 $arg2 }}
{{ $v := or
$arg1
$arg2
}}您还可以将 原始字符串字面值 分割到两行或多行。例如,这些是等价的:
{{ $msg := "This is line one.\nThis is line two." }}
{{ $msg := `This is line one.
This is line two.`
}}Nil
除了在比较中使用 nil 关键字外,您不能将其用作任何函数或方法的参数,也不能将其分配给变量。例如,这些是 nil 关键字的有效用法:
{{ if gt 42 nil }}
<p>42 大于 nil</p>
{{ end }}
{{ $pages := where .Site.RegularPages "Params.color" "ne" nil }}另一方面,这些是无效的:
{{ $a := nil }}
{{ add 3 nil }}
{{ nil | print}}上述动作会抛出错误。
变量
变量是用户定义的 标识符,前面加上美元符号 ($),表示在模板动作中初始化或分配的任何数据类型的值。例如,$foo 和 $bar 是变量。
使用 := 初始化变量,使用 = 将值分配给之前初始化的变量。例如:
{{ $total := 3 }}
{{ range slice 7 11 21 }}
{{ $total = add $total . }}
{{ end }}
{{ $total }} → 42在 if、range 或 with 块内初始化的变量的作用域仅限于该块。在这些块外初始化的变量的作用域为模板。
对于表示切片或映射的变量,使用 index 函数返回所需的值。
{{ $slice := slice "foo" "bar" "baz" }}
{{ index $slice 2 }} → baz
{{ $map := dict "a" "foo" "b" "bar" "c" "baz" }}
{{ index $map "c" }} → baz切片和数组从零开始;元素 0 是第一个元素。
对于表示映射或对象的变量,链接 标识符以返回所需的值或访问所需的方法。
{{ $map := dict "a" "foo" "b" "bar" "c" "baz" }}
{{ $map.c }} → baz
{{ $homePage := .Site.Home }}
{{ $homePage.Title }} → 我的主页标题如上所示,对象和方法名称是大写的。虽然不要求,但为了避免混淆,我们建议变量和映射键名以小写字母或下划线开头。
函数
函数在模板动作中使用,接受一个或多个参数并返回一个值。与方法不同,函数不与对象关联。
Go 的 text/template 和 html/template 包提供了一小组用于通用用途的函数、运算符和语句。有关详细信息,请参阅函数文档的 go-templates 部分。
Hugo 提供数百个按命名空间分类的自定义 函数。例如,strings 命名空间包括这些和其他函数:
| 函数 | 别名 |
|---|---|
strings.ToLower |
lower |
strings.ToUpper |
upper |
strings.Replace |
replace |
如上所示,常用函数有别名。在模板中使用别名以减少代码长度。
调用函数时,用空格将参数与函数以及参数彼此分开。例如:
{{ $total := add 1 2 3 4 }}方法
方法在模板动作中使用并与对象关联,接受零个或多个参数,要么返回值,要么执行操作。
最常访问的对象是 Page 和 Site 对象。这是每个对象可用 方法 的一小部分示例。
| 对象 | 方法 | 描述 |
|---|---|---|
Page |
Date |
返回给定页面的日期。 |
Page |
Params |
返回给定页面前言中定义的自定义参数的映射。 |
Page |
Title |
返回给定页面的标题。 |
Site |
Data |
返回由 data 目录中的文件组成的数据结构。 |
Site |
Params |
返回站点配置中定义的自定义参数的映射。 |
Site |
Title |
返回站点配置中定义的标题。 |
使用点 (.) 将方法链接到其对象,如下所示,请记住前导点表示 当前上下文。
{{ .Site.Title }} → 我的站点标题
{{ .Page.Title }} → 我的页面标题传递给大多数模板的上下文是 Page 对象,因此这等同于上一个示例:
{{ .Site.Title }} → 我的站点标题
{{ .Title }} → 我的页面标题某些方法接受参数。用空格将参数与方法分开。例如:
{{ $page := .Page.GetPage "/books/les-miserables" }}
{{ $page.Title }} → 悲惨世界注释
不要尝试使用 HTML 注释分隔符来注释模板代码。
Hugo 在渲染页面时会删除 HTML 注释,但首先会评估 HTML 注释分隔符内的任何模板代码。根据 HTML 注释分隔符内的模板代码,这可能会导致意外结果或导致构建失败。
模板注释类似于模板动作。成对的开始和结束大括号表示注释的开始和结束。例如:
{{/* 这是一个内联注释。*/}}
{{- /* 这是一个删除相邻空白的内联注释。*/ -}}注释内的代码不会被解析、执行或显示。注释可以是内联的,如上所示,也可以是块形式的:
{{/*
这是一个块注释。
*/}}
{{- /*
这是一个删除相邻空白的
块注释。
*/ -}}您不能将一个注释嵌套在另一个注释内。
要渲染 HTML 注释,请将字符串传递给 safeHTML 模板函数。例如:
{{ "<!-- 我是一个 HTML 注释。-->" | safeHTML }}
{{ printf "<!-- 这是 %s 站点。-->" .Site.Title | safeHTML }}包含
使用 template 函数包含一个或多个 Hugo 的 嵌入式模板:
{{ partial "google_analytics.html" . }}
{{ partial "opengraph" . }}
{{ partial "pagination.html" . }}
{{ partial "schema.html" . }}
{{ partial "twitter_cards.html" . }}使用 partial 或 partialCached 函数包含一个或多个 部分模板:
{{ partial "breadcrumbs.html" . }}
{{ partialCached "css.html" . }}在 layouts/_partials 目录中创建您的 部分 模板。
在上面的示例中,请注意我们将当前上下文(点)传递给每个模板。
示例
这组简化的示例展示了上述一些概念。有关具体示例,请参阅 函数、方法 和 模板 文档。
条件块
{{ $var := 42 }}
{{ if eq $var 6 }}
{{ print "var 是 6" }}
{{ else if eq $var 7 }}
{{ print "var 是 7" }}
{{ else if eq $var 42 }}
{{ print "var 是 42" }}
{{ else }}
{{ print "var 是其他值" }}
{{ end }}逻辑运算符
{{ $v1 := true }}
{{ $v2 := false }}
{{ $v3 := false }}
{{ $result := false }}
{{ if and $v1 $v2 $v3 }}
{{ $result = true }}
{{ end }}
{{ $result }} → false
{{ if or $v1 $v2 $v3 }}
{{ $result = true }}
{{ end }}
{{ $result }} → true循环
{{ $s := slice "foo" "bar" "baz" }}
{{ range $s }}
<p>{{ . }}</p>
{{ else }}
<p>集合为空</p>
{{ end }}要循环指定次数:
{{ $s := slice }}
{{ range 3 }}
{{ $s = $s | append . }}
{{ end }}
{{ $s }} → [0 1 2]重新绑定上下文
{{ $var := "foo" }}
{{ with $var }}
{{ . }} → foo
{{ else }}
{{ print "var 是假值" }}
{{ end }}要测试多个条件:
{{ $v1 := 0 }}
{{ $v2 := 42 }}
{{ with $v1 }}
{{ . }}
{{ else with $v2 }}
{{ . }} → 42
{{ else }}
{{ print "v1 和 v2 是假值" }}
{{ end }}访问站点参数
请参阅 Site 对象上的 Params 方法文档。
使用此站点配置:
baseURL: https://example.org
params:
author:
email: jsmith@example.org
name: John Smith
copyright-year: '2023'
layouts:
rfc_1123: Mon, 02 Jan 2006 15:04:05 MST
rfc_3339: '2006-01-02T15:04:05-07:00'
subtitle: 地球上最好的 Widgets
title: ABC Widgets
baseURL = 'https://example.org'
title = 'ABC Widgets'
[params]
copyright-year = '2023'
subtitle = '地球上最好的 Widgets'
[params.author]
email = 'jsmith@example.org'
name = 'John Smith'
[params.layouts]
rfc_1123 = 'Mon, 02 Jan 2006 15:04:05 MST'
rfc_3339 = '2006-01-02T15:04:05-07:00'
{
"baseURL": "https://example.org",
"params": {
"author": {
"email": "jsmith@example.org",
"name": "John Smith"
},
"copyright-year": "2023",
"layouts": {
"rfc_1123": "Mon, 02 Jan 2006 15:04:05 MST",
"rfc_3339": "2006-01-02T15:04:05-07:00"
},
"subtitle": "地球上最好的 Widgets"
},
"title": "ABC Widgets"
}
通过链接标识符访问自定义站点参数:
{{ .Site.Params.subtitle }} → 地球上最好的 Widgets
{{ .Site.Params.author.name }} → John Smith
{{ $layout := .Site.Params.layouts.rfc_1123 }}
{{ .Site.Lastmod.Format $layout }} → Tue, 17 Oct 2023 13:21:02 PDT访问页面参数
请参阅 Page 对象上的 Params 方法文档。
举例来说,考虑此前言:
---
date: 2023-10-17T15:11:37-07:00
params:
author:
email: jsmith@example.org
name: John Smith
display_related: true
key-with-hyphens: 必须使用 index 函数
title: 年度会议
---+++
date = 2023-10-17T15:11:37-07:00
title = '年度会议'
[params]
display_related = true
key-with-hyphens = '必须使用 index 函数'
[params.author]
email = 'jsmith@example.org'
name = 'John Smith'
+++{
"date": "2023-10-17T15:11:37-07:00",
"params": {
"author": {
"email": "jsmith@example.org",
"name": "John Smith"
},
"display_related": true,
"key-with-hyphens": "必须使用 index 函数"
},
"title": "年度会议"
}
title 和 date 字段是标准 前言字段,而其他字段是用户定义的。
{{ .Params.display_related }} → true
{{ .Params.author.email }} → jsmith@example.org
{{ .Params.author.name }} → John Smith在上面的模板示例中,每个键都是有效的标识符。例如,没有键包含连字符。要访问不是有效标识符的键,请使用 index 函数:
{{ index .Params "key-with-hyphens" }} → 必须使用 index 函数