Markdown 中的 Shortcodes
Shortcodes 是一种特殊的语法,允许你在 Markdown 文档中嵌入复杂的功能,而无需编写完整的 HTML 或 JavaScript 代码。它们像是内容模板的快捷方式。
什么是 Shortcodes?
Shortcodes 是由静态网站生成器(如 Hugo、Jekyll、Gatsby)提供的简短代码片段,可以在 Markdown 中调用预定义的功能或组件。
基本语法
不同平台的 shortcode 语法略有不同:
Hugo
{{< shortcode-name param1="value1" >}}
{{< shortcode-name param1="value1" >}}
内容
{{< /shortcode-name >}}Jekyll
{% shortcode_name param1='value1' %}
{% shortcode_name param1='value1' %}
内容
{% endshortcode_name %}Docusaurus / MDX
<ShortcodeName param1="value1" />
<ShortcodeName param1="value1">
内容
</ShortcodeName>常见 Shortcodes
图片和媒体
Hugo 图片 Shortcode
{{< figure src="/images/example.jpg" title="示例图片" caption="这是一个示例图片" >}}视频嵌入
{{< youtube "dQw4w9WgXcQ" >}}
{{< vimeo "123456789" >}}
{{< bilibili "BV1xx411c7mD" >}}音频播放器
{{< audio src="/audio/podcast.mp3" >}}提示和警告框
{{< note >}}
这是一个提示信息。
{{< /note >}}
{{< warning >}}
这是一个警告信息。
{{< /warning >}}
{{< danger >}}
这是一个危险警告。
{{< /danger >}}
{{< tip >}}
这是一个小技巧。
{{< /tip >}}代码示例
{{< highlight python "linenos=table,hl_lines=2-3" >}}
def hello_world():
print("Hello")
print("World")
{{< /highlight >}}
{{< code-tabs >}}
{{< code-tab lang="javascript" >}}
console.log("Hello World");
{{< /code-tab >}}
{{< code-tab lang="python" >}}
print("Hello World")
{{< /code-tab >}}
{{< /code-tabs >}}选项卡
{{< tabs >}}
{{< tab "选项卡 1" >}}
这是选项卡 1 的内容。
{{< /tab >}}
{{< tab "选项卡 2" >}}
这是选项卡 2 的内容。
{{< /tab >}}
{{< /tabs >}}折叠面板
{{< collapse "点击展开详情" >}}
这里是折叠的内容。
只有在用户点击时才会显示。
{{< /collapse >}}
{{< accordion >}}
{{< accordion-item "问题 1" >}}
答案 1
{{< /accordion-item >}}
{{< accordion-item "问题 2" >}}
答案 2
{{< /accordion-item >}}
{{< /accordion >}}引用和参考
{{< ref "path/to/page.md" >}}
{{< relref "sibling-page.md" >}}
{{< cite "book-reference" >}}平台特定 Shortcodes
Hugo Shortcodes
内置 Shortcodes
# 图片
{{< figure src="image.jpg" title="标题" >}}
# 推文嵌入
{{< tweet user="username" id="1234567890" >}}
# Instagram
{{< instagram "PostID" >}}
# Gist
{{< gist username "gist-id" >}}
# 高亮代码
{{< highlight go >}}
func main() {
fmt.Println("Hello")
}
{{< /highlight >}}
# 参数引用
{{< param "description" >}}自定义 Hugo Shortcode
创建 layouts/shortcodes/button.html:
<a href="{{ .Get "href" }}" class="button {{ .Get "class" }}">
{{ .Inner }}
</a>使用:
{{< button href="/download" class="primary" >}}
下载
{{< /button >}}Jekyll Shortcodes(Liquid 标签)
内置标签
{% include file.html %}
{% highlight ruby %}
def foo
puts 'bar'
end
{% endhighlight %}
{% link _posts/2024-01-15-article.md %}
{% post_url 2024-01-15-article %}自定义 Jekyll 标签
创建 _plugins/button_tag.rb:
module Jekyll
class ButtonTag < Liquid::Tag
def initialize(tag_name, params, tokens)
super
@params = params
end
def render(context)
"<button class='custom-button'>#{@params}</button>"
end
end
end
Liquid::Template.register_tag('button', Jekyll::ButtonTag)使用:
{% button Click Me %}Docusaurus / MDX
MDX 组件
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="apple" label="苹果">
这是苹果。
</TabItem>
<TabItem value="orange" label="橙子">
这是橙子。
</TabItem>
</Tabs>提示框
:::note
这是一个提示。
:::
:::tip
这是一个小技巧。
:::
:::info
这是信息提示。
:::
:::caution
这是警告。
:::
:::danger
这是危险警告。
:::代码块
```jsx title="src/App.js" {1-2,4}
import React from 'react';
import Layout from '@theme/Layout';
export default function App() {
return <Layout>Hello</Layout>;
}
\```Gatsby
内置组件
import { Link } from 'gatsby'
<Link to="/page-2/">Go to page 2</Link>插件组件
import { YouTube } from 'gatsby-plugin-youtube'
<YouTube videoId="dQw4w9WgXcQ" />VuePress
内置容器
::: tip
这是一个提示
:::
::: warning
这是一个警告
:::
::: danger
这是一个危险警告
:::
::: details
这是一个详情块
:::自定义容器
::: theorem 牛顿第一定律
假若施加于某物体的外力为零,则该物体的运动速度不变。
:::创建自定义 Shortcodes
Hugo 自定义 Shortcode
简单 Shortcode
layouts/shortcodes/highlight-box.html:
<div class="highlight-box">
{{ .Inner | markdownify }}
</div>使用:
{{< highlight-box >}}
这是**重要**内容。
{{< /highlight-box >}}带参数的 Shortcode
layouts/shortcodes/alert.html:
<div class="alert alert-{{ .Get "type" }}">
<strong>{{ .Get "title" }}</strong>
{{ .Inner }}
</div>使用:
{{< alert type="warning" title="注意" >}}
请小心操作!
{{< /alert >}}命名参数 Shortcode
layouts/shortcodes/card.html:
<div class="card">
{{ with .Get "image" }}
<img src="{{ . }}" alt="{{ $.Get "title" }}">
{{ end }}
<h3>{{ .Get "title" }}</h3>
<p>{{ .Inner }}</p>
{{ with .Get "link" }}
<a href="{{ . }}">了解更多</a>
{{ end }}
</div>使用:
{{< card title="我的卡片" image="/img/card.jpg" link="/details" >}}
这是卡片的描述内容。
{{< /card >}}Jekyll 自定义标签
简单标签
_plugins/highlight_tag.rb:
module Jekyll
class HighlightTag < Liquid::Block
def render(context)
content = super
"<div class='highlight-box'>#{content}</div>"
end
end
end
Liquid::Template.register_tag('highlight', Jekyll::HighlightTag)使用:
{% highlight %}
重要内容
{% endhighlight %}带参数的标签
_plugins/button_tag.rb:
module Jekyll
class ButtonTag < Liquid::Tag
def initialize(tag_name, params, tokens)
super
@params = parse_params(params)
end
def render(context)
url = @params['url']
text = @params['text']
color = @params['color'] || 'blue'
"<a href='#{url}' class='btn btn-#{color}'>#{text}</a>"
end
private
def parse_params(params)
Hash[params.scan(/(\w+)="([^"]+)"/)]
end
end
end
Liquid::Template.register_tag('button', Jekyll::ButtonTag)使用:
{% button url="/download" text="下载" color="green" %}MDX 自定义组件
React 组件
components/Callout.jsx:
export default function Callout({ type, title, children }) {
const colors = {
info: 'blue',
warning: 'yellow',
error: 'red',
success: 'green'
};
return (
<div className={`callout callout-${colors[type]}`}>
{title && <strong>{title}</strong>}
<div>{children}</div>
</div>
);
}使用:
import Callout from '@/components/Callout';
<Callout type="warning" title="注意">
这是一个重要的警告信息。
</Callout>最佳实践
1. 保持简洁
# 好的:简洁清晰
{{< note >}}
重要提示
{{< /note >}}
# 避免:过于复杂
{{< container type="note" style="background:blue;padding:20px" id="note-1" class="custom" >}}
重要提示
{{< /container >}}2. 提供清晰的参数
# 好的:明确的参数名
{{< video src="video.mp4" poster="thumbnail.jpg" width="800" >}}
# 避免:模糊的参数
{{< video "video.mp4" "thumbnail.jpg" "800" >}}3. 文档化你的 Shortcodes
创建 shortcode 文档:
# Shortcode 参考
## note
创建一个提示框。
**语法**:
\`\`\`
{{< note >}}
你的内容
{{< /note >}}
\`\`\`
**参数**:无
**示例**:
\`\`\`
{{< note >}}
这是一个重要提示。
{{< /note >}}
\`\`\`4. 提供回退选项
确保即使 shortcode 不起作用,内容仍然可读:
{{< video src="demo.mp4" >}}
[无法播放视频?点击下载](demo.mp4)
{{< /video >}}5. 测试跨平台兼容性
# 使用通用的 HTML 作为回退
<div class="note">
这在任何平台都能工作
</div>
# 平台特定的 shortcode 加条件
{{< if hugo >}}
{{< note >}}Hugo 样式{{< /note >}}
{{< else >}}
::: note
通用样式
:::
{{< end >}}常见 Shortcode 库
Hugo
- Hugo Easy Gallery: 图片画廊
- Hugo Shortcode Gallery: shortcode 集合
- Hugo Algolia: 搜索集成
Jekyll
- Jekyll Spaceship: 扩展 Markdown 功能
- Jekyll Include Cache: 优化 include 性能
- Jekyll Target Blank: 外部链接自动 blank
Universal
- Embed.ly: 通用媒体嵌入
- Shortcode.js: 客户端 shortcode 解析器
性能考虑
1. 避免过度嵌套
# 避免:深度嵌套
{{< tabs >}}
{{< tab "Tab 1" >}}
{{< note >}}
{{< highlight >}}
代码
{{< /highlight >}}
{{< /note >}}
{{< /tab >}}
{{< /tabs >}}
# 更好:扁平结构
{{< code-note lang="js" >}}
代码
{{< /code-note >}}2. 缓存重复内容
// Hugo shortcode 使用缓存
{{ $result := .Inner | markdownify }}
{{ $result }}3. 延迟加载
<!-- 延迟加载视频 -->
<div class="video-container" data-src="video.mp4">
<button onclick="loadVideo(this)">加载视频</button>
</div>调试 Shortcodes
Hugo 调试
{{ printf "%#v" . }} <!-- 打印所有变量 -->
{{ .Get 0 | printf "%#v" }} <!-- 打印第一个参数 -->Jekyll 调试
puts "Debug: #{@params.inspect}"MDX 调试
console.log('Props:', props);结论
Shortcodes 是扩展 Markdown 功能的强大工具。它们让你能够在保持内容可读性的同时,添加丰富的交互功能。选择适合你平台的 shortcode 系统,并遵循最佳实践来创建可维护的内容。