Shortcodes短代码是加强模板功能的简短的、可重用的代码片段, 您可以在内容内直接嵌入短代码。 某种意义上,可以认为短代理是页面和list模板基础内容文件中的中间件.

创建定制短代码

Hugo的内建短代码覆盖了很多常见-但不是全部-的用例. 幸运的是, Hugo提供了简单创建定制短代码以满足网站需求的能力.

文件位置

为创建短代码模板, 在代码组织layouts/shortcodes目录创建新的HTML模板. 请仔细考虑文件名称,短代码名会反应文件名称, 但是不包括 .html 扩展名. 比如, layouts/shortcodes/myshortcode.html 的代码会以{{< myshortcode />}} or {{% myshortcode /%}}的方式被调用, 依赖于所选择参数类型。

也可以在子目录中组织短代码, 比如,在layouts/shortcodes/boxes中. 这些短代码调用是会通过相对目录, 比如:

1
{{< boxes/square >}}

注意反斜线

短代码模板解析查询顺序

短代码模板的解析查询顺序简单些,仅仅查询如下两个地方:

  1. /layouts/shortcodes/<SHORTCODE>.html
  2. /themes/<THEME>/layouts/shortcodes/<SHORTCODE>.html

位置参数与命名参数

创建短代码可以使用下面的参数类型:

  • 位置参数
  • 命名参数
  • 位置参数或者命名参数 (具有"适应性")

带有位置参数的短代码中,参数的顺序很重要。 如果短代码只有一个必填值(例如下面的youtube短代码), 位置参数可以很好地工作,并且内容作者的键入次数更少

对于具有多个或可选参数的更复杂的布局,命名参数最有效. 命名参数虽然不那么简洁,但它们需要内容作者的更少的记忆,并且可以以任何顺序添加到短代码声明中。

对于复杂布局来说, 如果想允许用户重载默认参数值,允许两种类型的参数(比如说适应性很强的短代码)很有帮助,

访问参数

所有短代码可以通过.Get方法访问。传递个.Get方法的参数是一个键值(字符串)还是一个数值相应的依赖于您在访问命名参数还是位置参数.

通过名称访问参数, 请使用.Get 方法, 后面跟随引号括起的命名参数.

1
{{ .Get "class" }}

访问位置参数, 请使用 .Get方法, 后面跟随一个表示位置的数值, 请注意位置参数索引从零开始:

1
{{ .Get 0 }}

对第二个位置, 下面这样访问:

1
{{ .Get 1 }}

with 方法很方便,当输出依赖于设置了某参数:

1
{{ with .Get "class"}} class="{{.}}"{{ end }}

使用.Get 方法检查参数是否设置也很有帮助。当条件依赖于某个参数的值时特别有用:

1
{{ if or (.Get "title") (.Get "alt") }} alt="{{ with .Get "alt"}}{{.}}{{else}}{{.Get "title"}}{{end}}"{{ end }}

变量 .Inner

当使用了闭合的短代码时, .Inner变量被赋予了短代码开启和闭合括号之间的所有内容。 如果闭合短代码是必须的, 可以检查 .Inner的长度作为短代码存在的指示.

通过 .Inner变量定义的短代码也可以不使用内联内容、不使用闭合括号的自闭合模式来声明:

1
{{< innershortcode />}}

变量 .Params

更复杂的用例中, 短代码中变量 .Params 包含传递给短代码的参数的list. 可以使用下面逻辑访问更高范围层次的参数:

$.Params :可以访问直接传递给短代码声明的参数(比如youtube视频ID)

$.Page.Params
页面参数的引用; 这里的 “page” 引用的是短代码声明所在的内容文件(比如, 页面内容前言设定中 shortcode_color 字段可以通过 $.Page.Params.shortcode_color 访问)

$.Page.Site.Params :站点配置文件中定义的全局变量的引用

变量.IsNamedParams

变量 .IsNamedParams 检查短代码声明是否使用了有名参数,返回一个boolean值.

比如,创建image短代码,接受一个命名参数src或者第一个位置参数, 依赖于内容作者的喜好。 假设我们像下面这样调用 image 短代码:

1
{{< image src="images/my-image.jpg">}}

然后您可以包含下面代码作为短代码模板的一部分:

1
2
3
4
5
{{ if .IsNamedParams }}
<img src="{{.Get "src" }}" alt="">
{{ else }}
<img src="{{.Get 0}}" alt="">
{{ end }}

请看下面的使用.IsNamedParams参数的样例Vimeo 短代码.

可以使用变量 .Page获取所有的普通的页面变量 page variables

短代码可以嵌套。在嵌入的短代码中, 可以通过.Parent 变量访问上一级短代码上下文。这对于从根部继承常见的短代码参数很有帮助.

检查短代码是否存在

可以在页面模板中使用 .HasShortcode 参数来检查特定短代码是否在页面内使用。这个特性有时候有些帮助,比如想包含仅仅会被短代码使用的特定脚本或者样式表。

定制的短代码例子

下面是可以在/layouts/shortcodes中创建的不同类型的短代码的例子:

单-词例子 : year

假设想使得内容文件的copyright年份维持在当前年份, 而不需要持续的检查您的markdown文件。您的目标是下面这样调用短代码:

1
{{< year >}}
/layouts/shortcodes/year.html
1
2

{{ now.Format "2006" }}

单一位置参数例子: youtube

嵌入的视频在markdown内容中是常见的,不过很块就会使得内容混乱。下面是Hugo内置的YouTube短代码的使用方式:

1
{{< youtube 09jf3ow9jfw >}}

会调用/layouts/shortcodes/youtube.html的模板:

/layouts/shortcodes/youtube.html
1
2
3
4
5

<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>
youtube-embed.html
1
2
3
4
5
6
7
8

<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短代码。 目标是像下面这样在内容文件中调用:

content-image.md
1
2

{{< img src="/media/spf13.jpg" title="Steve Francia" >}}

创建了短代码文件/layouts/shortcodes/img.html,调用下面模板:

/layouts/shortcodes/img.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19

<!-- 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 -->

会这样呈现HTML:

img-output.html
1
2
3
4
5
6
7

<figure>
    <img src="/media/spf13.jpg"  />
    <figcaption>
        <h4>Steve Francia</h4>
    </figcaption>
</figure>

单一的可适应行例子 : vimeo

1
2
{{< vimeo 49718712 >}}
{{< vimeo id="49718712" class="flex-video" >}}

会调用 /layouts/shortcodes/vimeo.html的模板:

/layouts/shortcodes/vimeo.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10

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

HTML呈现如下:

vimeo-iframes.html
1
2
3
4
5
6
7

<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内建的built-in shortcode

highlight-example.md
1
2
3
4
5
6

{{< highlight html >}}
  <html>
    <body> This HTML </body>
  </html>
{{< /highlight >}}

highlight短代码使用下面的代码,已经包含在Hugo中:

1
{{ .Get 0 | highlight .Inner  }}

呈现的HTML输出例子代码块如下:

syntax-highlighted.html
1
2
3
4
5

<div class="highlight" style="background: #272822"><pre style="line-height: 125%"><span style="color: #f92672">&lt;html&gt;</span>
    <span style="color: #f92672">&lt;body&gt;</span> This HTML <span style="color: #f92672">&lt;/body&gt;</span>
<span style="color: #f92672">&lt;/html&gt;</span>
</pre></div>

嵌套的短代码: 图片库

Hugo的.Parent 短代码变量返回值依赖于调用的短代码是否在一个parent上级短代码的上下文中. 这样提供了通过的短代码参数继承模型.

下面例子是编造的,但是展示了概念。假设有一个gallery短代码,期望一个命名为class的参数:

layouts/shortcodes/gallery.html
1
2
3
4

<div class="{{.Get "class"}}">
  {{.Inner}}
</div>

另外假设有img短代码具有单一命名参数src, 你想在gallery或者其他短代码中使用, 由此parent定义了每个img的上下文:

layouts/shortcodes/img.html
1
2
3
4
5
6
7

{{- $src := .Get "src" -}}
{{- with .Parent -}}
  <img src="{{$src}}" class="{{.Get "class"}}-image">
{{- else -}}
  <img src="{{$src}}">
{{- end }}

然后可以在内容中如下调用短代码:

1
2
3
4
5
{{< gallery class="content-gallery" >}}
  {{< img src="/images/one.jpg" >}}
  {{< img src="/images/two.jpg" >}}
{{< /gallery >}}
{{< img src="/images/three.jpg" >}}

输出如下的HTML. 注意头两个img短代码继承了父级短代码gallery调用而设置的content-galleryclass值,但是第三个图像仅仅有src:

1
2
3
4
5
<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模板函数和.Position变量来获得有用的短代码错误信息:

1
2
3
4
{{ with .Get "name" }}
{{ else }}
{{ errorf "missing value for param 'name': %s" .Position }}
{{ end }}

当上面代码有错误时,您会在终端看见如下的ERROR日志:

1
ERROR 2018/11/07 10:05:55 missing value for param name: "/Users/bep/dev/go/gohugoio/hugo/docs/content/en/variables/shortcodes.md:32:1"

更多短代码例子

更多短代码例子可以参考spf13.com的短代码目录Hugo 文档的短代码.

内联的短代码

从Hugo 0.52版本开始, 可以实现内联的短代码 – 就在内容文件的里面的短代码. 这对于仅仅使用一次的脚本有帮助.

这个特性默认是关闭的, 但是可以在您的站点配置中启用:

config.
     
1
enableInlineShortcodes: true
1
enableInlineShortcodes = true
1
2
3
{
   "enableInlineShortcodes": true
}

由于安全原因,这个特性默认是禁用的。Hugo的模板处理所用的安全模型假设模板作者是可信任的、到那时内容文件不是,所以模板对于异常的输入信息是插入安全的。但是在很多情景下您也具有对内容的完全控制,这样打开enableInlineShortcodes = true参数开关被认为是安全的。不过这还是需要的事项: 这允许特许的Go Text templates 在内容文件内执行。

启用以后,可以在内容文件中这样做:

1
{{< time.inline >}}{{ now }}{{< /time.inline >}}

上面例子会打印当前日期和是时间.

请注意内联的短代码内容是作为Go语言Text模板解析和执行的,具有和常规短代码模板相同的上下文。

也就意味这当前页面可以通过.Page.Title等访问。这也意味着没有"嵌套内联模板"的概念.

相同的内联短代码模板也可以在相同的内容文件的后面重用,如果有必要使用不同的参数,使用自我闭合的模式.

1
{{< time.inline />}}