news 2026/9/19 10:21:49

Hugo 短代码 .Inner:在开闭标签之间提取与渲染内容

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Hugo 短代码 .Inner:在开闭标签之间提取与渲染内容

Hugo 短代码 .Inner:在开闭标签之间提取与渲染内容

【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo

导读

.Inner是 Hugo 短代码(shortcode)模板中的核心变量之一,它返回短代码开标签与闭标签之间的原始内容,适用于任何带闭标签的短代码调用。本文以 docs/content/en/methods/shortcode/Inner.md 为骨架,结合 hugolib/shortcode.go 等源码,系统讲解.Inner的数据结构、取用姿势、空白字符处理,以及通过RenderStringmarkdownify或将整个短代码按 Markdown 渲染({{% %}}写法)来把 Inner 内容从纯文本升级为真正的 HTML,并给出可直接复制的完整示例。


一、.Inner 是什么

在 Hugo 中,短代码有两种常见调用形态:自闭合(无内容)成对(有内容)。当你在 Markdown 源文件中写成对短代码时,比如:

{{</* card title="Product Design" */>}} We design the **best** widgets in the world. {{</* /card */>}}

开标签{{</* card ... */>}}与闭标签{{</* /card */>}}之间的所有内容——We design the **best** widgets in the world.——就是该短代码的Inner 内容。在短代码模板中,通过.Inner即可取用这段内容。

从源码看,.Inner的类型是template.HTML,由 hugolib/shortcode.go 中ShortcodeWithPage结构体定义:

// ShortcodeWithPage is the "." context in a shortcode template. type ShortcodeWithPage struct { Params any Inner template.HTML Page page.Page Parent *ShortcodeWithPage Name string IsNamedParams bool // ... }

ShortcodeWithPage就是短代码模板执行时的.上下文,因此模板里可以同时访问:

成员含义
.Inner开闭标签之间的原始内容(template.HTML类型)
.Get "title"按键取短代码参数(hugolib/shortcode.go 中的Get方法)
.Params全部参数
.Page当前页面对象
.Parent父级短代码上下文(支持嵌套短代码)
.Ordinal该短代码在页面中的零基序号
.Store短代码作用域的临时存储(替代已废弃的.Scratch

需要留意:.Inner只有在对短代码的调用包含闭标签时才有效。如果调用是自闭合的(没有闭标签、没有内容),.Inner为空。源码 hugolib/shortcode.go 甚至会抛出错误提示:"shortcode %q does not evaluate .Inner or .InnerDeindent, yet a closing tag was provided",即模板中使用了.Inner却未提供闭标签时会收到明确的构建错误,方便你定位问题。

1.1 相关的 InnerDeindent

在 hugolib/shortcode.go 中还有一个InnerDeindent()方法:当短代码在源文件中带有缩进时,它返回去除缩进后的 Inner 内容。它按行遍历,把以scp.indentation(开标签前的缩进)开头的行去掉该前缀。若没有缩进则直接返回.Inner。如果你的短代码内容会被嵌入到缩进敏感的场景(如 Markdown 代码块),可以考虑使用InnerDeindent而非Inner


二、基础用法:把 Inner 作为纯文本输出

最直接的用法是在短代码模板中直接输出.Inner。例如定义一个卡片短代码 layouts/_shortcodes/card.html(对应前面content/services.md中的调用):

<div class="card"> {{ with .Get "title" }} <div class="card-title">{{ . }}</div> {{ end }} <div class="card-content"> {{ .Inner | strings.TrimSpace }} </div> </div>

渲染结果:

<div class="card"> <div class="card-title">Product Design</div> <div class="card-content"> We design the **best** widgets in the world. </div> </div>

这里有两个要点:

  1. strings.TrimSpace处理换行。开闭标签之间的内容在 Markdown 中常带有前导/尾随换行(取决于书写位置),直接输出会破坏布局。strings.TrimSpace会移除首尾的空白(包括回车与换行),使 Inner 内容紧贴card-content。对应的模板函数定义可参考 tpl/strings/strings.go 的 TrimSpace 实现。
  2. 默认情况下 Inner 中的 Markdown 不会被渲染。示例里**best**是 Markdown 加粗语法,但输出仍是字面**best**——因为.Inner只是原始内容(template.HTML),Hugo 不会自动对它做 Markdown 转换。

2.1 源码视角:Inner 内容的收集

在 hugolib/shortcode.go 的渲染逻辑中,Hugo 会遍历解析出的 inner 数据段:普通字符串直接拼接,遇到嵌套短代码则递归渲染后拼接,最终写入data.Inner。同时,对于以 Markdown 渲染模式({{% %}},见下文)调用、且内容不含换行的场景,源码还会用正则\A<p>(.*)</p>\n\z剥离包裹的<p>标签(hugolib/shortcode.go),避免单行内容被包成段落块。这解释了为什么“按 Markdown 渲染”时单行与多行 Inner 的输出形态会不同。


三、用 RenderString 把 Inner 渲染成 HTML

要让 Inner 中的 Markdown 真正变成 HTML,最简单的方式是把它交给Page.RenderString方法处理。修改上面的模板:

<div class="card"> {{ with .Get "title" }} <div class="card-title">{{ . }}</div> {{ end }} <div class="card-content"> {{ .Inner | strings.TrimSpace | .Page.RenderString }} </div> </div>

渲染结果:

<div class="card"> <div class="card-title">Product design</div> <div class="card-content"> We produce the <strong>best</strong> widgets in the world. </div> </div>

RenderString把 Inner 中经过 TrimSpace 处理后的 Markdown 文本渲染为 HTML(**best**<strong>best</strong>)。关于RenderString的完整说明可参考 docs/content/en/methods/page/RenderString.md。

注意:示例标题从 "Product Design" 变为 "Product design",这只是示例文案本身的差异,并非RenderString的副作用——RenderString只负责把 Markdown 渲染为 HTML,不会改写标题文本。

3.1 markdownify 与 RenderString 的取舍

原文档明确指出:你也可以用markdownify函数替代RenderString方法,但后者更灵活。从 tpl/transform/transform.go 的实现可以看到:

// Markdownify renders s from Markdown to HTML. func (ns *Namespace) Markdownify(ctx context.Context, s any) (template.HTML, error) { home := ns.deps.Site.Home() if home == nil { panic("home must not be nil") } ss, err := home.RenderString(ctx, s) if err != nil { return "", err } // Strip if this is a short inline type of text. bb := ns.deps.ContentSpec.TrimShortHTML([]byte(ss), "markdown") return helpers.BytesToHTML(bb), nil }

从源码看,markdownify内部本质上是基于 Home 页面调用RenderString,并额外通过TrimShortHTML对短小行内文本做<p>剥离处理。而RenderStringPage对象的方法,允许指定渲染器与上下文(如使用当前页面的配置),因此在需要精确控制渲染行为、处理块级内容时更具灵活性。简单行内文本可用markdownify,复杂块级内容建议用Page.RenderString


四、替代写法:用 {{% %}} 按 Markdown 渲染整个短代码

除了在模板内用RenderString二次加工,Hugo 还提供第二种思路:把整个短代码调用声明为 Markdown 渲染模式。将内容中的{{</* */>}}改为{{%/* */%}}记号(docs/content/en/content-management/shortcodes 中有完整记号说明):

{{%/* card title="Product Design" */%}} We design the **best** widgets in the world. {{%/* /card */%}}

此时 Hugo 会把整个短代码(包括输出结果)作为 Markdown 渲染,因此需要做两处配合修改。

4.1 第一步:允许 raw HTML

由于短代码模板输出的是 HTML,而整体又要走 Markdown 渲染管线,必须先在配置中放行 raw HTML:

{{< code-toggle file=hugo >}} [markup.goldmark.renderer] unsafe = true {{< /code-toggle >}}

对应hugo.toml的写法:

[markup.goldmark.renderer] unsafe = true

安全说明:此配置之所以"unsafe"是因为它允许 Markdown 内容中嵌入未经转义的原始 HTML;如果你完全掌控内容源(例如个人站点或可信作者团队),风险可控。Hugo 的安全模型可参考 docs/content/en/about/security/_index.md。

4.2 第二步:遵循 CommonMark 缩进与 HTML 块规则

因为整个短代码被当作 Markdown 渲染,模板输出必须符合 CommonMark 规范 中关于缩进代码块原始 HTML 块的规则:

<div class="card"> {{ with .Get "title" }} <div class="card-title">{{ . }}</div> {{ end }} <div class="card-content"> {{ .Inner | strings.TrimSpace }} </div> </div>

与基础版模板对比,差异是微妙但必须的(见下面对照):

--- layouts/_shortcodes/a.html +++ layouts/_shortcodes/b.html @@ -1,8 +1,9 @@ <div class="card"> {{ with .Get "title" }} - <div class="card-title">{{ . }}</div> + <div class="card-title">{{ . }}</div> {{ end }} <div class="card-content"> - {{ .Inner | strings.TrimSpace | .Page.RenderString }} + + {{ .Inner | strings.TrimSpace }} </div> </div>

具体变化有三处:

  1. 调整缩进.card-title从 4 空格缩进改为 2 空格,避免被 CommonMark 识别为缩进代码块(4 空格及以上会被当作代码块处理)。
  2. 添加空行:在.Inner前增加空行,确保 Inner 内容作为独立的 HTML 块处理,而不是与相邻标签粘连。
  3. 移除RenderString{{% %}}记号下,不要再对 Inner 做RenderStringmarkdownify处理——因为整个短代码已经被 Hugo 作为 Markdown 渲染,Inner 的 Markdown 会在这一轮渲染中自然转换。若再手动调用RenderString会造成双重渲染。

[!NOTE] 使用 Markdown 记号({{% %}})调用短代码时,不要用RenderStringmarkdownify处理 Inner 值。


五、两种方案的对比与选择

维度方案 A:.Inner | .Page.RenderString方案 B:{{% %}}+ unsafe
调用记号{{</* */>}}{{%/* */%}}
是否需配置unsafe = true
是否需遵循 CommonMark 缩进/HTML 块规则否(模板输出即最终 HTML)
Inner 中 Markdown 渲染方式在模板内显式调用RenderString/markdownify由整段短代码的 Markdown 渲染自动完成
灵活性高:可精确控制渲染时机、上下文与输出结构低:输出受 Markdown 渲染管线约束
典型场景内容块、卡片、引用等需要精细控制的组件希望在短代码内外统一走 Markdown 处理流程
  • 想要精确控制、不引入全局配置,选方案 A(RenderString)。
  • 希望 Markdown 与短代码输出统一处理、且内容源可信,选方案 B({{% %}}+unsafe = true)。
  • 无论哪种方案,都建议对.Inner先做strings.TrimSpace,避免开闭标签旁的多余换行影响布局。

六、易错点小结

  1. 忘记闭标签:模板里用到.Inner而调用处没有闭标签,Hugo 会报错:"shortcode does not evaluate .Inner ... yet a closing tag was provided"(hugolib/shortcode.go)。
  2. Inner 默认不渲染 Markdown:直接输出.Inner得到的是字面文本(含**等 Markdown 语法),需要RenderStringmarkdownify(或在{{% %}}模式下自动处理)。
  3. 未处理首尾换行:开闭标签之间的换行会原样进入 Inner,记得strings.TrimSpace
  4. {{% %}}模式下重复渲染:已整体按 Markdown 渲染时,再对 Inner 调用RenderString/markdownify会双重转换。
  5. CommonMark 缩进陷阱{{% %}}模式下模板输出的 4 空格缩进可能被当作代码块,务必保持 2 空格缩进并正确使用空行分隔 HTML 块。

参考资料与源码索引

  • 本文核心依据:docs/content/en/methods/shortcode/Inner.md
  • .Inner字段定义与InnerDeindent实现:hugolib/shortcode.go
  • Inner 内容收集与渲染(含<p>剥离逻辑):hugolib/shortcode.go、hugolib/shortcode.go
  • markdownify实现(内部调用RenderString):tpl/transform/transform.go
  • Page.RenderString方法:docs/content/en/methods/page/RenderString.md
  • 短代码记号说明:docs/content/en/content-management/shortcodes
  • Hugo 安全模型:docs/content/en/about/security/_index.md
  • 短代码模板目录约定:layouts/_shortcodes/

【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 10:19:25

深度卷积网络多模态轨迹预测:从设计到落地的工程实践

自动驾驶轨迹预测这个方向&#xff0c;我从早期做规则-based的卡尔曼滤波跟踪开始&#xff0c;到后来转深度学习方案&#xff0c;踩过的坑确实不少。今天想聊的这个项目&#xff0c;核心是用深度卷积网络做多模态轨迹预测——说白了&#xff0c;就是让车不仅能猜出前方行人或车…

作者头像 李华
网站建设 2026/9/19 10:19:22

Windows下Docker Desktop完全指南:安装、汉化、迁移与排错

1. 安装之前先想清楚&#xff1a;Docker Desktop在Windows上到底是个什么东西 先说一个很多人都踩过的误区&#xff1a;以为Docker Desktop就是一个"Windows下的Docker安装包"&#xff0c;装完就能跑容器。实际上&#xff0c;Docker Desktop是一个带图形界面的管理壳…

作者头像 李华
网站建设 2026/9/19 10:17:41

SAC强化学习用于交通流量预测的MATLAB实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 10:17:19

江苏电商公司办公家具靠谱供应商:凡赫家具用户力荐

最近几年&#xff0c;越来越多江苏地区的企业在采购办公家具时&#xff0c;都会搜索高管办公区全套家具推荐厂家、抗污耐脏办公桌面家具推荐厂家、适合国企单位用的靠谱办公家具品牌&#xff0c;就是希望能找到适配自身需求、品质稳定的供应商。随着江苏电商产业快速发展&#…

作者头像 李华