创建你自己的短代码
短代码是一种将模板整合到小型、可重用代码片段中的方法,您可以直接将其嵌入到内容中。
创建自定义短代码
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
方法,后跟一个数字位置,请记住位置参数是从零开始的:
{{ .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
- 指的是页面的参数;此处的“页面”指的是声明短代码的内容文件(例如,内容前题中
shortcode_color
字段可以通过$.Page.Params.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 短代码 使用的代码:
{{< 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>
<div class="embed video-player">
<iframe class="youtube-player" type="text/html"
width="640" height="385"
src="https://www.youtube.com/embed/09jf3ow9jfw"
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> This 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> This 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
的调用设置的 content-gallery
的 class
值,而第三个 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>Hello, my name is {{ . }}.</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"
行内短代码
您也可以在行内实现您的短代码——例如,在您使用它们的 Content 文件中。这对于您只需要在一个地方使用的脚本很有用。
此功能默认情况下是禁用的,但可以在您的站点配置中启用:
security:
enableInlineShortcodes: true
[security]
enableInlineShortcodes = true
{
"security": {
"enableInlineShortcodes": true
}
}
出于安全原因,它默认情况下是禁用的。Hugo 模板处理使用的安全模型假设模板作者是可信的,但内容文件不可信,因此模板可以防止格式错误的输入数据注入。但在大多数情况下,您也完全控制内容,那么 enableInlineShortcodes = true
将被认为是安全的。但这是一件需要注意的事情:它允许从内容文件中执行即席的 Go 文本模板 。
启用后,您可以在内容文件中执行此操作:
{{< time.inline >}}{{ now }}{{< /time.inline >}}
以上将打印当前日期和时间。
请注意,行内短代码的内部内容将被解析并作为 Go 文本模板执行,其上下文与常规短代码模板相同。
这意味着可以通过 .Page.Title
等访问当前页面。这也意味着没有“嵌套行内短代码”的概念。
如果需要,可以使用自闭合语法在同一个内容文件中稍后重用相同的行内短代码,并使用不同的参数:
{{< time.inline />}}