跳到主要内容

短代码

短代码(Shortcodes)是在 Markdown 内容中插入复杂内容的方式。本章将介绍如何使用和创建短代码。

什么是短代码?

Markdown 格式虽然简洁,但有些功能无法直接实现,比如嵌入视频、图片画廊、代码高亮等。短代码允许你在 Markdown 中插入这些复杂功能,同时保持内容的可读性。

短代码的基本语法:

<!-- 无参数 -->
{{< shortcode >}}

<!-- 有参数 -->
{{< shortcode param1="value1" param2="value2" >}}

<!-- 包含内容 -->
{{< shortcode >}}
内部内容
{{< /shortcode >}}

内置短代码

Hugo 提供了一些常用的内置短代码。

figure - 图片

{{< figure src="/images/photo.jpg" title="图片标题" alt="图片描述" >}}

完整参数:

{{< figure 
src="/images/photo.jpg"
link="https://example.com"
target="_blank"
title="点击查看大图"
alt="风景照片"
caption="这是图片说明"
attr="作者"
attrlink="https://example.com/author"
width="600px"
height="400px"
class="my-image"
>}}

youtube - YouTube 视频

{{< youtube id="VIDEO_ID" >}}

<!-- 或直接使用 URL -->
{{< youtube https://www.youtube.com/watch?v=VIDEO_ID >}}

<!-- 带参数 -->
{{< youtube id="VIDEO_ID" autoplay="true" start="30" >}}

vimeo - Vimeo 视频

{{< vimeo id="VIDEO_ID" >}}

gist - GitHub Gist

<!-- 整个 Gist -->
{{< gist username gist_id >}}

<!-- 特定文件 -->
{{< gist username gist_id filename.py >}}

instagram - Instagram 嵌入

{{< instagram POST_ID >}}

twitter - Twitter 嵌入

{{< twitter user="username" id="TWEET_ID" >}}

qr - QR 码生成

Hugo 内置 QR 码生成短代码,可以在页面中嵌入 QR 码图片:

<!-- 基本用法 -->
{{< qr >}}
https://gohugo.io
{{< /qr >}}

<!-- 使用参数 -->
{{< qr text="https://gohugo.io" level="high" />}}

<!-- 生成当前页面的 QR 码 -->
{{< qr text="{{ .Permalink }}" />}}

可选参数:

参数说明默认值
text要编码的文本内容-
level容错级别:low、medium、quartile、highmedium
targetPath输出路径自动生成

param - 参数引用

param 短代码用于在内容中引用 Front Matter 或站点配置中的参数:

<!-- 引用页面的自定义参数 -->
{{< param "author" >}}

<!-- 引用嵌套参数 -->
{{< param "social.github" >}}

<!-- 引用站点参数 -->
{{< param "description" >}}

在 Front Matter 中定义参数:

---
title: "我的文章"
author: "张三"
social:
github: "zhangsan"
twitter: "zhangsan_dev"
---

在内容中使用:

本文作者是 {{< param "author" >}},GitHub 账号是 {{< param "social.github" >}}。

details - 折叠内容

details 短代码用于创建可折叠的内容区域:

{{< details summary="点击查看详情" >}}
这里是隐藏的内容,支持 **Markdown** 格式。

- 列表项 1
- 列表项 2
{{< /details >}}

参数说明:

参数说明
summary折叠区域标题(必填)
open是否默认展开,默认 false
{{< details summary="默认展开的内容" open=true >}}
这段内容默认是展开的。
{{< /details >}}

highlight - 代码高亮

{{< highlight python "linenos=table,hl_lines=2 3" >}}
def hello():
print("Hello, Hugo!")
return True
{{< /highlight >}}

参数说明:

  • linenos=table:显示行号(表格形式)
  • linenos=inline:显示行号(内联形式)
  • hl_lines="2 3":高亮第 2、3 行

code - 代码文件

{{< code file="main.py" lang="python" >}}
def main():
print("Hello")
{{< /code >}}

ref 和 relref - 页面引用

<!-- 绝对 URL -->
[关于页面]({{< ref "about.md" >}})

<!-- 相对 URL -->
[关于页面]({{< relref "about.md" >}})

<!-- 引用特定章节 -->
[章节]({{< relref "posts/my-post#introduction" >}})

创建自定义短代码

自定义短代码放在 layouts/shortcodes/ 目录下。

简单短代码

创建一个简单的提示框短代码:

layouts/shortcodes/note.html

<div class="note">
<strong>注意:</strong> {{ .Inner }}
</div>

使用:

{{< note >}}这是一个重要提示{{< /note >}}

带参数的短代码

创建一个带类型参数的提示框:

layouts/shortcodes/alert.html

{{ $type := .Get "type" | default "info" }}
{{ $title := .Get "title" | default "" }}

<div class="alert alert-{{ $type }}">
{{ with $title }}
<div class="alert-title">{{ . }}</div>
{{ end }}
<div class="alert-content">
{{ .Inner | markdownify }}
</div>
</div>

使用:

{{< alert type="warning" title="警告" >}}
这是一条警告信息,支持 **Markdown** 格式。
{{< /alert >}}

{{< alert type="success" >}}
操作成功完成!
{{< /alert >}}

获取参数的方式

<!-- 获取位置参数 -->
{{ .Get 0 }} <!-- 第一个参数 -->
{{ .Get 1 }} <!-- 第二个参数 -->

<!-- 获取命名参数 -->
{{ .Get "title" }}
{{ .Get "class" }}

<!-- 使用默认值 -->
{{ .Get "type" | default "info" }}

<!-- 检查参数是否存在 -->
{{ if .Get "image" }}
<img src="{{ .Get "image" }}">
{{ end }}

处理内部内容

<!-- 原样输出 -->
{{ .Inner }}

<!-- 解析 Markdown -->
{{ .Inner | markdownify }}

<!-- 转义 HTML -->
{{ .Inner | plainify }}

无闭合标签的短代码

创建图片画廊短代码:

layouts/shortcodes/gallery.html

{{ $images := .Get "images" }}
{{ $class := .Get "class" | default "gallery" }}

<div class="{{ $class }}">
{{ range split $images "," }}
{{ $img := trim . " " }}
<figure>
<img src="{{ $img }}" alt="">
</figure>
{{ end }}
</div>

使用:

{{< gallery images="/img/1.jpg, /img/2.jpg, /img/3.jpg" class="my-gallery" >}}

实用短代码示例

代码演示

创建一个带标题和说明的代码块:

layouts/shortcodes/codedemo.html

{{ $lang := .Get "lang" | default "text" }}
{{ $title := .Get "title" | default "代码示例" }}
{{ $desc := .Get "desc" }}

<div class="code-demo">
<div class="code-header">
<span class="code-title">{{ $title }}</span>
{{ with $desc }}
<span class="code-desc">{{ . }}</span>
{{ end }}
</div>
<div class="code-content">
{{ highlight .Inner $lang "" }}
</div>
</div>

使用:

{{< codedemo lang="python" title="Hello World" desc="简单的打印示例" >}}
print("Hello, World!")
{{< /codedemo >}}

折叠内容

创建可折叠的内容区域:

layouts/shortcodes/collapse.html

{{ $title := .Get "title" | default "点击展开" }}
{{ $open := .Get "open" | default false }}

<details {{ if $open }}open{{ end }}>
<summary>{{ $title }}</summary>
<div class="collapse-content">
{{ .Inner | markdownify }}
</div>
</details>

使用:

{{< collapse title="查看详细说明" >}}
这里是详细说明内容,支持 **Markdown** 格式。
{{< /collapse >}}

外部链接

创建带图标的链接:

layouts/shortcodes/extlink.html

{{ $url := .Get 0 }}
{{ $text := .Get 1 | default $url }}

<a href="{{ $url }}" target="_blank" rel="noopener noreferrer" class="external-link">
{{ $text }}
<svg class="icon" viewBox="0 0 24 24">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15 3 21 3 21 9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
</a>

使用:

{{< extlink "https://gohugo.io" "Hugo 官网" >}}

图片对比

创建并排对比的图片展示:

layouts/shortcodes/compare.html

{{ $before := .Get "before" }}
{{ $after := .Get "after" }}
{{ $beforeLabel := .Get "beforeLabel" | default "之前" }}
{{ $afterLabel := .Get "afterLabel" | default "之后" }}

<div class="image-compare">
<div class="compare-item">
<img src="{{ $before }}" alt="{{ $beforeLabel }}">
<span class="label">{{ $beforeLabel }}</span>
</div>
<div class="compare-item">
<img src="{{ $after }}" alt="{{ $afterLabel }}">
<span class="label">{{ $afterLabel }}</span>
</div>
</div>

使用:

{{< compare before="/img/before.jpg" after="/img/after.jpg" beforeLabel="优化前" afterLabel="优化后" >}}

视频嵌入

创建通用的视频嵌入短代码:

layouts/shortcodes/video.html

{{ $src := .Get "src" }}
{{ $type := .Get "type" | default "video/mp4" }}
{{ $poster := .Get "poster" }}
{{ $width := .Get "width" | default "100%" }}
{{ $controls := .Get "controls" | default true }}
{{ $autoplay := .Get "autoplay" | default false }}
{{ $loop := .Get "loop" | default false }}

<video
width="{{ $width }}"
{{ if $poster }}poster="{{ $poster }}"{{ end }}
{{ if $controls }}controls{{ end }}
{{ if $autoplay }}autoplay{{ end }}
{{ if $loop }}loop{{ end }}
>
<source src="{{ $src }}" type="{{ $type }}">
您的浏览器不支持视频播放。
</video>

使用:

{{< video src="/videos/demo.mp4" poster="/img/poster.jpg" controls="true" >}}

卡片组件

创建信息卡片:

layouts/shortcodes/card.html

{{ $title := .Get "title" }}
{{ $image := .Get "image" }}
{{ $link := .Get "link" }}
{{ $class := .Get "class" | default "" }}

<div class="card {{ $class }}">
{{ with $image }}
<div class="card-image">
<img src="{{ . }}" alt="{{ $title }}">
</div>
{{ end }}
<div class="card-content">
{{ with $title }}
<h3 class="card-title">{{ . }}</h3>
{{ end }}
<div class="card-body">
{{ .Inner | markdownify }}
</div>
{{ with $link }}
<a href="{{ . }}" class="card-link">了解更多</a>
{{ end }}
</div>
</div>

使用:

{{< card title="Hugo" image="/img/hugo-logo.png" link="https://gohugo.io" >}}
Hugo 是世界上最快的静态网站生成器。
{{< /card >}}

嵌套短代码

短代码可以嵌套使用,创建复杂的组件结构。

基本嵌套

{{< gallery class="image-gallery" >}}
{{< image src="/images/photo1.jpg" alt="照片1" >}}
{{< image src="/images/photo2.jpg" alt="照片2" >}}
{{< image src="/images/photo3.jpg" alt="照片3" >}}
{{< /gallery >}}

创建可嵌套的短代码

父级短代码需要处理 .Inner 中的子短代码:

layouts/shortcodes/gallery.html

<div class="gallery {{ .Get "class" | default "default-gallery" }}">
{{ .Inner }}
</div>

layouts/shortcodes/image.html

{{ $src := .Get "src" }}
{{ $alt := .Get "alt" }}
<figure class="gallery-item">
<img src="{{ $src }}" alt="{{ $alt }}" loading="lazy">
{{ with $alt }}
<figcaption>{{ . }}</figcaption>
{{ end }}
</figure>

访问父级上下文

子短代码可以通过 $.Parent 访问父级短代码的上下文:

<!-- 父级短代码 layouts/shortcodes/card.html -->
<div class="card {{ .Get "class" }}">
{{ .Inner }}
</div>
{{ .Scratch.Set "card-width" (.Get "width" | default "full") }}

<!-- 子短代码 layouts/shortcodes/card-image.html -->
{{ $width := $.Parent.Scratch.Get "card-width" }}
<img src="{{ .Get "src" }}" class="card-image width-{{ $width }}">

嵌套示例:选项卡组件

选项卡组件是嵌套短代码的典型应用场景:

使用方式

{{< tabs >}}
{{< tab name="JavaScript" >}}
console.log("Hello");
{{< /tab >}}

{{< tab name="Python" >}}
print("Hello")
{{< /tab >}}

{{< tab name="Go" >}}
fmt.Println("Hello")
{{< /tab >}}
{{< /tabs >}}

父级短代码 layouts/shortcodes/tabs.html

{{ $id := substr (md5 .Inner) 0 8 }}
<div class="tabs">
<div class="tab-buttons" role="tablist">
{{ range .InnerDeindent }}
{{ if eq .ShortcodeName "tab" }}
<button
class="tab-button {{ if eq .Ordinal 0 }}active{{ end }}"
role="tab"
data-tab="{{ $id }}-{{ .Ordinal }}">
{{ .Get "name" }}
</button>
{{ end }}
{{ end }}
</div>
<div class="tab-contents">
{{ .Inner }}
</div>
</div>

子级短代码 layouts/shortcodes/tab.html

<div class="tab-content" data-tab-index="{{ .Ordinal }}">
{{ .Inner | markdownify }}
</div>

短代码最佳实践

命名规范

使用小写字母和连字符:

layouts/shortcodes/
├── alert.html
├── code-demo.html
├── image-gallery.html
└── video-player.html

参数验证

检查必需参数:

{{ if not (.Get "src") }}
{{ errorf "shortcode 'video' requires 'src' parameter" }}
{{ end }}

提供默认值

{{ $width := .Get "width" | default "100%" }}
{{ $class := .Get "class" | default "default-class" }}

支持 Markdown

内部内容通常应该支持 Markdown:

{{ .Inner | markdownify }}

添加 CSS 类

允许用户自定义样式:

<div class="shortcode-name {{ .Get "class" }}">
...
</div>

内联短代码

内联短代码允许在内容文件中直接定义短代码模板,无需创建单独的模板文件。

启用内联短代码

出于安全考虑,内联短代码默认是禁用的。如果信任内容作者,可以在配置中启用:

[security]
enableInlineShortcodes = true

定义和使用

内联短代码以 .inline 结尾命名,在内容中定义后可以重复使用:

---
title: "我的文章"
---

<!-- 定义内联短代码 -->
{{< date.inline ":date_medium" >}}
{{- now | time.Format (.Get 0) -}}
{{< /date.inline >}}

<!-- 再次调用 -->
今天是 {{< date.inline ":date_full" />}}。

渲染结果:

<p>Jan 30, 2025.</p>
<p>今天是 Thursday, January 30, 2025。</p>

内联短代码的特点

  • 定义时立即执行一次,后续可重复调用
  • 可以访问所有标准短代码方法
  • 不能嵌套使用内联短代码
  • 适合简单的一次性模板需求

实际应用示例

动态日期显示

{{< year.inline >}}
{{- now.Year -}}
{{< /year.inline >}}

版权所有 © {{< year.inline />}} 我的博客。

条件内容

{{< env.inline "production" >}}
{{- if eq hugo.Environment (.Get 0) -}}
<script src="/analytics.js"></script>
{{- end -}}
{{< /env.inline >}}

短代码与 Markdown 渲染

两种语法

<!-- 使用 {{< >}}:内部内容不渲染 Markdown -->
{{< highlight html >}}
**这是粗体**(不会被渲染)
{{< /highlight >}}

<!-- 使用 {{% %}}:内部内容渲染 Markdown -->
{{% note %}}
**这是粗体**(会被渲染为粗体)
{{% /note %}}

选择建议

  • 纯 HTML 输出:使用 {{< >}}
  • 需要 Markdown 渲染:使用 {{% %}}

对目录的影响

使用不同语法会影响目录生成:

  • {{% %}} 语法:内部 Markdown 标题会被包含在目录中
  • {{< >}} 语法:内部 Markdown 标题不会出现在目录中

示例:

{{% section %}}
## 这会出现在目录中
{{% /section %}}

{{< section >}}
## 这不会出现在目录中
{{< /section >}}

小结

本章介绍了 Hugo 短代码的核心知识:

  1. 内置短代码提供了常用的嵌入功能
  2. 自定义短代码可以扩展 Markdown 功能
  3. 短代码支持参数和内部内容
  4. 使用 markdownify 处理 Markdown 内容
  5. 内联短代码可以在内容中定义模板
  6. 短代码可以嵌套使用构建复杂组件
  7. 合理使用短代码可以保持内容的简洁性

下一章将学习 Hugo 的配置系统。