原样透传
创建透传渲染钩子,处理 Goldmark 透传扩展捕获的文本片段,例如在构建时渲染公式。
概述
Hugo 使用 Goldmark 把 Markdown 渲染为 HTML。Goldmark 支持通过自定义扩展来扩展核心功能。Passthrough 扩展会捕获并保留被定界符包围的原始 Markdown 文本片段,连定界符本身也一并保留。这类片段称为透传元素(passthrough element)。
取决于所选用的定界符,Hugo 会把透传元素归类为块级(block)或行内(inline)。看下面这个刻意构造的例子:
This is a
\[block\]
passthrough element with opening and closing block delimiters.
This is an \(inline\) passthrough element with opening and closing inline delimiters.需要在项目配置中启用 Passthrough 扩展,并为每种透传元素类型(block 或 inline)定义起始与结束定界符。例如:
[markup.goldmark.extensions.passthrough]
enable = true
[markup.goldmark.extensions.passthrough.delimiters]
block = [['\[', '\]'], ['$$', '$$']]
inline = [['\(', '\)']]上例为 block 定义了两组定界符,在 Markdown 中使用其中任意一组都可以。
Passthrough 扩展常与 MathJax 或 KaTeX 显示引擎搭配使用,用来渲染以 LaTeX 标记语言书写的数学表达式。
要启用透传元素的自定义渲染,需创建透传渲染钩子。
上下文
透传渲染钩子模板接收以下上下文:
Attributes- (
map)Markdown 属性,需要按下面的方式配置站点后才可用:[markup.goldmark.parser.attribute] block = trueHugo 只为块级透传元素填充
Attributes映射;Markdown 属性不适用于行内元素。 Inner- (
string)透传元素的内层内容,不含定界符。 Ordinal- (
int)透传元素在页面中的序号,从 0 开始。 Page- (
page)当前页面的引用。 PageInner- (
page)通过RenderShortcodes方法嵌套的页面的引用。详见下文 PageInner details。 Position- (
string)透传元素在页面内容中的位置。 Type- (
string)透传元素类型,取值为block或inline。
示例
与其在浏览器端用 MathJax 或 KaTeX 通过 JavaScript 渲染数学标记,不如创建一个透传渲染钩子,在构建时调用 transform.ToMath 函数完成渲染:
{{- $opts := dict "output" "htmlAndMathml" "displayMode" (eq .Type "block") }}
{{- with try (transform.ToMath .Inner $opts) }}
{{- with .Err }}
{{- errorf "Unable to render mathematical markup to HTML using the transform.ToMath function. The KaTeX display engine threw the following error: %s: see %s." . $.Position }}
{{- else }}
{{- .Value }}
{{- $.Page.Store.Set "hasMath" true }}
{{- end }}
{{- end -}}随后在基础模板中,按条件在 head 元素内引入 KaTeX 的 CSS:
<head>
{{ $noop := .WordCount }}
{{ if .Page.Store.Get "hasMath" }}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.18.4/dist/katex.min.css" integrity="sha384-u1zONI5gPXUx0UKI62c75/zww972y0v2rSK5ZYlVdS6xEuWDeZWUI66v6t1gvlXJ" crossorigin="anonymous">
{{ end }}
</head>上面的写法用了一个空操作(noop)语句,强制先完成内容渲染,再用 Store.Get 方法检查 hasMath 的值。
尽管可以像上面那样用一个模板加条件逻辑处理,也可以为每种透传元素 Type 创建单独的模板:
layouts/
└── _markup/
├── render-passthrough-block.html
└── render-passthrough-inline.htmlPageInner details
PageInner 的主要用途是相对于被包含的页面来解析链接与页面资源。例如可以创建一个「包含」短代码,用多个内容文件拼装一个页面,同时为脚注与目录保留全局上下文:先用位置参数取出要包含的页面逻辑路径,再调用该页面的 RenderShortcodes 方法,取不到页面时用 errorf 报错。
然后在 Markdown 中用 Markdown 记法调用这个短代码,被包含页面的路径写在位置参数里。渲染 /posts/post-2 时触发的任何渲染钩子,调用 Page 会得到 /posts/post-1,调用 PageInner 则会得到 /posts/post-2。
PageInner 在不适用时会回退为 Page 的值,并且始终有返回值。它只对调用 RenderShortcodes 方法的短代码有意义,并且必须以 Markdown 记法调用该短代码。