HUGO
Menu
GitHub 87548 stars Mastodon

模板入門介紹

Hugo 模板語法的入門介紹。
We did a complete overhaul of Hugo’s template system in v0.146.0. We’re working on getting all of the relevant documentation up to date, but until then, see this page.

template(模板)是包�?template actions(模板動作)的文件,位於項目、主題或模塊�?layouts 目錄內�

模板使用 變量函數方法 將您的內容、資源和數據轉換為已發布的頁面。

Hugo 使用 Go 的 text/templatehtml/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 對象提供方法來返回值或執行操作。

當前上下文

在模板中,點 (.) 表示當前上下文。

layouts/page.html
<h2>{{ .Title }}</h2>

在上面的示例中,點表示 Page 對象,我們調用其 Title 方法來返回 前言 中定義的標題。

當前上下文可能在模板中發生變化。例如,在模板的頂部,上下文可能是 Page 對象,但我們在 rangewith 塊中將上下文重新綁定為其他值或對象。

layouts/page.html
<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>

模板上下文

rangewith 塊中,您可以通過在點前添加美元符號 ($) 來訪問傳遞給模板的上下文:

layouts/page.html
{{ with "foo" }}
  <p>{{ $.Title }} - {{ . }}</p>
{{ end }}

Hugo 將此渲染為:

<p>我的頁面標題 - foo</p>

在繼續閱讀之前,請確保您徹底理解 上下文 的概念。新手用戶最常見的模板錯誤與上下文有關。

動作

在上面的示例中,成對的開始和結束大括號表示模板動作的開始和結束,模板動作是模板內的數據評估或控制結構。

模板動作可以包含字面值(布爾值字符串整數浮點數)、當前上下文變量函數方法nil 關鍵字。

layouts/page.html
{{ $convertToLower := true }}
{{ if $convertToLower }}
  <h2>{{ strings.ToLower .Title }}</h2>
{{ end }}

在上面的示例中:

  • $convertToLower 是一個變量
  • true 是一個字面布爾值
  • if 是控制結構的開始
  • strings.ToLower 是一個將所有字符轉換為小寫的函數
  • TitlePage 對象上的一個方法
  • end 是控制結構的結束

Hugo 將上述內容渲染為:

  
  
    <h2>我的頁面標題</h2>
  

空白

注意到上一個示例中的空行和縮進了嗎?雖然在生產環境中通常會對輸出進行壓縮,因此這些空白無關緊要,但您可以使用帶連字符的模板動作分隔符來刪除相鄰的空白:

layouts/page.html
{{- $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

ifrangewith 塊內初始化的變量的作用域僅限於該塊。在這些塊外初始化的變量的作用域為模板。

對於表示切片或映射的變量,使用 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 }}

方法

方法在模板動作中使用並與對象關聯,接受零個或多個參數,要麼返回值,要麼執行操作。

最常訪問的對象是 PageSite 對象。這是每個對象可用 方法 的一小部分示例。

對象 方法 描述
Page Date 返回給定頁面的日期。
Page Params 返回給定頁面前言中定義的自定義參數的映射。
Page Title 返回給定頁面的標題。
Site Data 返回由 data 目錄中的文件組成的數據結構。
Site Params 返回站點配置中定義的自定義參數的映射。
Site Title 返回站點配置中定義的標題。

使用點 (.) 將方法鏈接到其對象,如下所示,請記住前導點表示 當前上下文

layouts/page.html
{{ .Site.Title }} → 我的站點標題
{{ .Page.Title }} → 我的頁面標題

傳遞給大多數模板的上下文是 Page 對象,因此這等同於上一個示例:

layouts/page.html
{{ .Site.Title }} → 我的站點標題
{{ .Title }} → 我的頁面標題

某些方法接受參數。用空格將參數與方法分開。例如:

layouts/page.html
{{ $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" . }}

使用 partialpartialCached 函數包含一個或多個 部分模板

{{ partial "breadcrumbs.html" . }}
{{ partialCached "css.html" . }}

layouts/_partials 目錄中創建您的 部分 模板。

在上面的示例中,請注意我們將當前上下文(點)傳遞給每個模板。

示例

這組簡化的示例展示了上述一些概念。有關具體示例,請參閱 函數方法模板 文檔。

條件塊

請參閱 ifelseend 的文檔。

{{ $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 }}

邏輯運算符

請參閱 andor 的文檔。

{{ $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

循環

請參閱 rangeelseend 的文檔。

{{ $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]

重新綁定上下文

請參閱 withelseend 的文檔。

{{ $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": "年度會議"
}

titledate 字段是標准 前言字段,而其他字段是用戶定義的。

通過 鏈接 標識符 訪問自定義字段(在需要時):

{{ .Params.display_related }} → true
{{ .Params.author.email }} → jsmith@example.org
{{ .Params.author.name }} → John Smith

在上面的模板示例中,每個鍵都是有效的標識符。例如,沒有鍵包含連字符。要訪問不是有效標識符的鍵,請使用 index 函數:

{{ index .Params "key-with-hyphens" }} → 必須使用 index 函數

Last updated: January 1, 0001
Improve this page