创建UI助手

本页解释了如何创建用于页面模板(布局或部分)的 UI helper。helper 是一个 JavaScript 函数,Handlebars 在模板中遇到 helper 调用时会调用它。

助手剖析

helper 必须定义为 UI 包中 helpers 目录中的一个 JavaScript 文件。文件名不包括文件扩展名,将作为函数名。例如,如果 helper 位于 helpers/join.js 中,则函数的名称将为 join

您不必将 helper 注册为 Antora 会自动处理。此自动行为取代了此 Handlebars API 调用(您不必执行此调用):

Handlebars.registerHelper('join', function () { ... })

helper 文件应该只导出一个默认函数。函数在文件中的名称并不重要。

下面是一个辅助函数的模板,您可以使用它作为起点:

new-helper.js
'use strict'

module.exports = () => {
  return true
}

函数的返回值将在模板的逻辑中使用。如果 helper 在条件语句中使用,它应该返回一个布尔值(如前面的示例所示)。如果使用 helper 创建输出,它应该返回一个字符串。如果 helper 在迭代循环中使用,它应该返回一个集合。

现在,我们可以在模板中使用条件 helper ,如下所示:

{{#if (new-helper)}}
always true!
{{/if}}

在 helper 函数调用周围总是需要圆括号(除非在 Handlebars 中隐含它们)。

helper 可以通过接受模板上下文作为最后一个参数来访问模板中的顶级变量。顶级变量存储在此对象的 data.root 属性中。

new-helper.js
'use strict'

module.exports = ({ data: { root } }) => {
  return root.site.url === 'https://docs.example.org'
}

现在我们的条件会改变:

{{#if (new-helper)}}
Only true if the site URL is https://docs.example.org.
{{/if}}

helper 还可以接受输入参数。这些参数会在上下文对象之前插入参数列表中。 Handlebars 仅使用模板传递的输入参数调用函数,因此重要的是使用固定数量的参数。否则,上下文对象的位置将会跳来跳去。

new-helper.js
'use strict'

module.exports = (urlToCheck, { data: { root } }) => {
  return root.site.url === urlToCheck
}

现在我们可以接受要检查的 URL 作为输入参数:

{{#if (new-helper 'https://docs.example.org')}}
Only true if the site URL matches the one specified.
{{/if}}

您可以查阅 Handlebars语言指南 ,了解有关创建帮助程序的更多信息。

在助手中使用内容目录

您可以在 helper 中直接使用 Antora 的内容目录来处理其他页面和资源。让我们定义一个 helper ,它组装具有在 page-tags 属性中定义的给定标记的页面集合。helper 调用看起来像这样:

{{#each (pages-with-tag 'tutorial')}}

我们首先在一个名为 pages-with-tag.js 的文件中定义这个 helper 。在第一次迭代中,我们将让它返回来自 Antora 内容目录的原始虚拟文件对象集合。用以下内容填充文件:

pages-with-tag.js
'use strict'

// 包含指定的标签
module.exports = (tag, { data }) => {
  const { contentCatalog } = data.root
  return contentCatalog.getPages(({ asciidoc, out }) => {
    if (!out || !asciidoc) return
    const pageTags = asciidoc.attributes['page-tags']
    return pageTags && pageTags.split(', ').includes(tag)
  })
}

在这里,我们获取对内容目录的引用,然后使用 getPage() 方法按我们的标准过滤页面。始终检查存在 out 属性,以确保页面可以发布是很好的做法。

下面是在模板中如何使用这个 helper :

{{#each (pages-with-tag 'tutorial')}}
<a href="{{{relativize ./pub.url}}}">{{{./asciidoc.doctitle}}}</a>
{{/each}}

您将注意到集合中的页面对象不同于典型的页面 UI 模型。我们可以在返回集合之前将每个页面转换为页面 UI 模型。让我们再次编写扩展,这次通过 Antora 的 buildPageUiModel 函数运行每个页面:

pages-with-tag.js
'use strict'

module.exports = (tag, { data }) => {
  const { contentCatalog, site } = data.root
  const pages = contentCatalog.getPages(({ asciidoc, out }) => {
    if (!out || !asciidoc) return
    const pageTags = asciidoc.attributes['page-tags']
    return pageTags && pageTags.split(', ').includes(tag)
  })
  const { buildPageUiModel } = require.main.require('@antora/page-composer/build-ui-model')
  return pages.map((page) => buildPageUiModel(site, page, contentCatalog))
}

在这种情况下,item 对象的用法更简单、更熟悉:

{{#each (pages-with-tag 'tutorial')}}
<a href="{{{relativize ./url}}}">{{{./doctitle}}}</a>
{{/each}}

使用此 helper 作为基础,您可以实现各种自定义和自定义集合。

请记住,使用该模板的每个页面都将调用您将使用的任何 helper 。这可能会影响性能。如果在站点的每个页面上都调用它,请确保该操作是有效的,以避免减慢站点生成速度。

作为使用 helper 的替代方案,您可能需要考虑编写 Antora 扩展是否是更好的选择。