創建你自己的短代碼
短代碼是一種將模板整合成小型、可重用片段的方式,可以直接嵌入你的內容中。
創建自訂短代碼
Hugo 內建的短代碼涵蓋了許多常見的用例,但並非所有情境。幸運的是,Hugo 允許你輕鬆創建自訂短代碼,以滿足網站的需求。
檔案位置
要創建一個短代碼,請將 HTML 模板放在 layouts/shortcodes
目錄中。請仔細考慮檔案名稱,因為短代碼的名稱將與檔案名稱相同,但不包含 .html
擴展名。例如,layouts/shortcodes/myshortcode.html
可以這樣調用:{{< myshortcode />}}
或 {{% myshortcode /%}}
。
你可以將短代碼組織在子目錄中,例如在 layouts/shortcodes/boxes
目錄中,這些短代碼可以透過相對路徑來調用,例如:
{{< boxes/square >}}
請注意前綴的斜線。
模板查找順序
Hugo 根據短代碼名稱、當前輸出格式和語言來選擇短代碼模板。以下是一些範例,按從具體到一般的順序排列。列表底部是最不具體的路徑。
短代碼名稱 | 輸出格式 | 語言 | 模板路徑 |
---|---|---|---|
foo | html | en | layouts/shortcodes/foo.en.html |
foo | html | en | layouts/shortcodes/foo.html.html |
foo | html | en | layouts/shortcodes/foo.html |
foo | html | en | layouts/shortcodes/foo.html.en.html |
短代碼名稱 | 輸出格式 | 語言 | 模板路徑 |
---|---|---|---|
foo | rss | en | layouts/shortcodes/foo.en.xml |
foo | rss | en | layouts/shortcodes/foo.rss.xml |
foo | rss | en | layouts/shortcodes/foo.en.html |
foo | rss | en | layouts/shortcodes/foo.rss.en.xml |
foo | rss | en | layouts/shortcodes/foo.xml |
foo | rss | en | layouts/shortcodes/foo.html.en.html |
foo | rss | en | layouts/shortcodes/foo.html.html |
foo | rss | en | layouts/shortcodes/foo.html |
請注意,主題或模組提供的模板會優先於其他模板。
位置參數與命名參數
你可以使用以下類型的參數來創建短代碼:
- 位置參數
- 命名參數
- 位置或命名參數
對於位置參數,參數的順序非常重要。如果短代碼只有一個必填值,位置參數可以減少內容作者的輸入量。
對於有多個或選填參數的複雜佈局,命名參數更為合適。雖然命名參數較長,但它們讓內容作者更容易理解,且可以以任何順序在短代碼中進行設置。
允許兩種參數類型的組合在複雜佈局中很有用,這樣你可以設定預設值,並讓使用者輕鬆覆蓋這些值。
訪問參數
所有短代碼參數都可以通過 .Get
方法訪問。使用 .Get
方法時,根據是訪問命名參數還是位置參數,需要傳遞字符串或數字。
要按名稱訪問參數,使用 .Get
方法,後接命名參數作為引號字符串:
{{ .Get "class" }}
要按位置訪問參數,使用 .Get
並傳遞數字,請記住位置參數是從 0 開始計數的:
{{ .Get 0 }}
對於第二個位置,你可以直接使用:
{{ .Get 1 }}
with
在當輸出依賴於某個參數時非常有用:
{{ with .Get "class" }} class="{{ . }}"{{ end }}
.Get
也可以用來檢查某個參數是否已提供。這對於根據某些值的存在與否進行條件判斷非常有用:
{{ if or (.Get "title") (.Get "alt") }} alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "title" }}{{ end }}"{{ end }}
.Inner
.Inner
方法返回開關短代碼標籤之間的內容。若 .Inner
返回的內容非空白,可進行如下判斷:
{{ if strings.ContainsNonSpace .Inner }}
Inner is not empty
{{ end }}
.Params
.Params
方法用於返回傳遞給短代碼的參數,這對於更複雜的用例非常有幫助。你還可以使用以下邏輯訪問更高範圍的參數:
$.Params
:這是直接傳遞給短代碼的參數(例如 YouTube 視頻 ID)。$.Page.Params
:指頁面參數;這裡的「頁面」是指包含短代碼的內容檔案(例如,可以通過$.Page.Params.shortcode_color
訪問內容 Front Matter 中的shortcode_color
欄位)。$.Site.Params
:指的是在網站配置中定義的參數。
.IsNamedParams
.IsNamedParams
方法檢查短代碼是否使用了命名參數,並返回一個布林值。
例如,你可以創建一個 image
短代碼,根據內容作者的偏好,接受 src
命名參數或第一個位置參數。假設 image
短代碼是這樣調用的:
{{< image src="images/my-image.jpg" >}}
你可以在短代碼模板中包含如下代碼:
{{ if .IsNamedParams }}
<img src="{{ .Get "src" }}" alt="">
{{ else }}
<img src="{{ .Get 0 }}" alt="">
{{ end }}
參見下面的 Vimeo 短代碼範例,以了解 .IsNamedParams
的具體應用。
短代碼也可以嵌套。在嵌套短代碼中,你可以使用 .Parent
方法訪問父短代碼上下文。這對於根目錄的繼承非常有用。
檢查短代碼是否存在
你可以通過在頁面模板中調用 .HasShortcode
方法來檢查該頁面是否使用了特定的短代碼,並提供短代碼名稱。當你希望只在使用該短代碼時包括特定的腳本或樣式時,這非常有用。
自訂短代碼範例
以下是可以在 /layouts/shortcodes
目錄中的短代碼模板文件中創建的不同類型的短代碼範例。
單字範例:year
假設你希望在內容文件中保持版權年份的最新狀態,而不必持續檢查 Markdown。你的目標是能夠這樣調用短代碼:
{{< year >}}
{{ now.Format "2006" }}
單一位置參數範例:youtube
嵌入影片是 Markdown 內容中的常見元素。以下是 Hugo 內建 YouTube 短代碼使用的代碼範例:youtubeshortcode:
{{< youtube 09jf3ow9jfw >}}
會加載位於 /layouts/shortcodes/youtube.html
的模板:
<div class="embed video-player">
<iframe class="youtube-player" type="text/html" width="640" height="385" src="https://www.youtube.com/embed/{{ index .Params 0 }}" allowfullscreen frameborder="0">
</iframe>
</div>
單一命名範例:image
假設你想要創建自己的 img
短代碼,而不是使用 Hugo 內建的 figure
短代碼。你的目標是能夠在內容檔案中像下面這樣呼叫該短代碼:
{{< img src="/media/spf13.jpg" title="Steve Francia" >}}
你已經在 /layouts/shortcodes/img.html
創建了短代碼,並且該模板載入了以下內容:
<!-- image -->
<figure {{ with .Get "class" }}class="{{ . }}"{{ end }}>
{{ with .Get "link" }}<a href="{{ . }}">{{ end }}
<img src="{{ .Get "src" }}" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" }}{{ end }}"{{ end }} />
{{ if .Get "link" }}</a>{{ end }}
{{ if or (or (.Get "title") (.Get "caption")) (.Get "attr") }}
<figcaption>{{ if isset .Params "title" }}
<h4>{{ .Get "title" }}</h4>{{ end }}
{{ if or (.Get "caption") (.Get "attr") }}<p>
{{ .Get "caption" }}
{{ with .Get "attrlink" }}<a href="{{ . }}"> {{ end }}
{{ .Get "attr" }}
{{ if .Get "attrlink" }}</a> {{ end }}
</p> {{ end }}
</figcaption>
{{ end }}
</figure>
<!-- image -->
這樣將會渲染為:
<figure>
<img src="/media/spf13.jpg" />
<figcaption>
<h4>Steve Francia</h4>
</figcaption>
</figure>
單一彈性範例:vimeo
{{< vimeo 49718712 >}}
{{< vimeo id="49718712" class="flex-video" >}}
這將會載入位於 /layouts/shortcodes/vimeo.html
的模板:
{{ if .IsNamedParams }}
<div class="{{ if .Get "class" }}{{ .Get "class" }}{{ else }}vimeo-container{{ end }}">
<iframe src="https://player.vimeo.com/video/{{ .Get "id" }}" allowfullscreen></iframe>
</div>
{{ else }}
<div class="{{ if len .Params | eq 2 }}{{ .Get 1 }}{{ else }}vimeo-container{{ end }}">
<iframe src="https://player.vimeo.com/video/{{ .Get 0 }}" allowfullscreen></iframe>
</div>
{{ end }}
這樣將會渲染為:
<div class="vimeo-container">
<iframe src="https://player.vimeo.com/video/49718712" allowfullscreen></iframe>
</div>
<div class="flex-video">
<iframe src="https://player.vimeo.com/video/49718712" allowfullscreen></iframe>
</div>
配對範例:highlight
以下是來自 highlight
的範例,這是 Hugo 內建的短代碼之一。
{{< highlight html >}}
<html>
<body> 這是 HTML </body>
</html>
{{< /highlight >}}
highlight
短代碼的模板使用以下代碼,這是 Hugo 預設已經包含的:
{{ .Get 0 | highlight .Inner }}
渲染後的 HTML 範例代碼區塊將會如下所示:
<div class="highlight" style="background: #272822"><pre style="line-height: 125%"><span style="color: #f92672"><html></span>
<span style="color: #f92672"><body></span> 這是 HTML <span style="color: #f92672"></body></span>
<span style="color: #f92672"></html></span>
</pre></div>
嵌套短代碼:圖像畫廊
Hugo 的 .Parent
短代碼方法提供了當短代碼在父級短代碼的上下文中被呼叫時,能夠訪問父級短代碼的上下文,這提供了一個繼承模型。
以下範例是構造出來的,但能夠展示這個概念。假設你有一個 gallery
短代碼,並且它預期一個名為 class
的參數:
<div class="{{ .Get "class" }}">
{{ .Inner }}
</div>
你還有一個 img
短代碼,它有一個名為 src
的參數,你想要在 gallery
和其他短代碼中呼叫它,這樣父代碼就能定義每個 img
的上下文:
{{- $src := .Get "src" -}}
{{- with .Parent -}}
<img src="{{ $src }}" class="{{ .Get "class" }}-image">
{{- else -}}
<img src="{{ $src }}">
{{- end -}}
然後你可以在內容中這樣呼叫短代碼:
{{< gallery class="content-gallery" >}}
{{< img src="/images/one.jpg" >}}
{{< img src="/images/two.jpg" >}}
{{< /gallery >}}
{{< img src="/images/three.jpg" >}}
這將會輸出以下 HTML。注意到前兩個 img
短代碼繼承了由父級 gallery
設定的 class
值 content-gallery
,而第三個 img
只使用了 src
:
<div class="content-gallery">
<img src="/images/one.jpg" class="content-gallery-image">
<img src="/images/two.jpg" class="content-gallery-image">
</div>
<img src="/images/three.jpg">
短代碼中的錯誤處理
使用 errorf
模板函數與 Name
和 Position
短代碼方法來生成有用的錯誤訊息:
{{ with .Get "name" }}
<p>你好,我的名字是 {{ . }}。</p>
{{ else }}
{{ errorf "The %q shortcode requires a 'name' argument. See %s" .Name .Position }}
{{ end }}
當上述失敗時,你將看到類似以下的 ERROR
訊息:
ERROR The "greeting" shortcode requires a 'name' argument. See "/home/user/project/content/_index.md:12:1"
行內短代碼
你也可以在內容文件中實現行內短代碼 – 例如,當你只需要在某一個地方使用它們時。這對於只需要一次的腳本來說非常有用。
此功能預設是禁用的,但可以在你的網站配置中啟用:
security:
enableInlineShortcodes: true
[security]
enableInlineShortcodes = true
{
"security": {
"enableInlineShortcodes": true
}
}
預設是禁用的,出於安全原因。Hugo 的模板處理所使用的安全模型假設模板作者是受信任的,但內容文件不是,因此模板可以安全地防範來自不當輸入資料的注入攻擊。但在大多數情況下,你對內容也擁有完全控制權,這時 enableInlineShortcodes = true
會被視為安全的。不過這是需要注意的:它允許從內容文件執行即時 Go 文本模板。
一旦啟用,你可以在內容文件中這樣操作:
{{< time.inline >}}{{ now }}{{< /time.inline >}}
上述代碼將輸出當前的日期和時間。
注意,行內短代碼的內部內容會像普通短代碼模板一樣作為 Go 文本模板進行解析和執行,並使用相同的上下文。
這意味著可以通過 .Page.Title
等來訪問當前頁面。這也意味著沒有「嵌套行內短代碼」的概念。
相同的行內短代碼可以在同一個內容文件中再次使用,並且可以根據需要使用不同的參數,這時可以使用自閉合語法:
{{< time.inline />}}