模板片段

Carson Gross

模板片段是服务器端渲染(SSR)模板库中一个相对少见的功能,它允许你渲染模板中的片段或部分内容,而不是整个模板。这个功能在超媒体驱动应用中非常有用,因为它允许你在内部为部分更新分解特定视图,而无需将模板片段提取到单独的文件中进行渲染,从而避免创建大量单独的模板文件。

通过将所有HTML保存在单个文件中,也更容易理解功能的工作原理。这遵循了行为局部性设计原则。

动机

让我们看看模板片段如何在一个名为chill模板(一种用于Java的冷门模板语言)中帮助我们构建超媒体驱动应用。

这是一个简单的chill模板/contacts/detail.html,用于显示联系人:

/contacts/detail.html
<html>
    <body>
        <div hx-target="this">
          #if contact.archived
          <button hx-patch="/contacts/${contact.id}/unarchive">取消归档</button>
          #else
          <button hx-delete="/contacts/${contact.id}">归档</button>
          #end
        </div>
        <h3>联系人</h3>
        <p>${contact.email}</p>
    </body>
</html>

在模板中,我们有一个归档功能,根据联系人的归档状态,我们显示"归档"或"取消归档"按钮,两者都由htmx驱动,并向不同的端点发出HTTP请求。

当我们点击显示的任一按钮时,我们希望用更新后的按钮替换包含该按钮的div中的内容。(注意div上的hx-target="this",因此我们将该div的innerHTML作为替换目标。)这将有效地在"归档"和"取消归档"之间切换。

现在,不幸的是,如果我们只想渲染按钮而不是模板的其余部分,通常需要将按钮拆分到它们自己的模板文件中,并在此模板中包含它,如下所示:

/contacts/detail.html
<html>
    <body>
        <div hx-target="this">
          #include archive-ui.html
        </div>
        <h3>联系人</h3>
        <p>${contact.email}</p>
    </body>
</html>
/contacts/archive-ui.html
#if contact.archived
<button hx-patch="/contacts/${contact.id}/unarchive">取消归档</button>
#else
<button hx-delete="/contacts/${contact.id}">归档</button>
#end

现在我们有两个模板。我们现在可以单独渲染archive-ui.html模板,但这种拆分降低了归档功能的可见性:当只看detail.html模板时,不太明显发生了什么。

当这种分解走向极端时,会导致相当多的小模板片段,总体上变得难以管理和理解。

模板片段来拯救

为了解决这个问题,chill模板有一个#fragment指令。这个指令允许你在模板中指定一个内容块,并仅渲染该部分内容

使用片段的/contacts/detail.html
<html>
    <body>
        <div hx-target="this">
          #fragment archive-ui
            #if contact.archived
            <button hx-patch="/contacts/${contact.id}/unarchive">取消归档</button>
            #else
            <button hx-delete="/contacts/${contact.id}">归档</button>
            #end
          #end
        </div>
        <h3>联系人</h3>
        <p>${contact.email}</p>
    </body>
</html>

在模板中定义了这个片段后,我们现在可以渲染整个模板:

  Contact c = getContact();
  ChillTemplates.render("/contacts/detail.html", "contact", c);

或者我们可以只渲染模板的archive-ui片段

  Contact c = getContact();
  ChillTemplates.render("/contacts/detail.html#archive-ui", "contact", c);

当我们要渲染联系人的整个详情页面时,会使用第一个选项。

当处理归档/取消归档操作并希望仅重新渲染按钮时,我们会使用第二个选项。

请注意,通过使用片段,我们能够将UI保持在一个文件中,并确切地了解该功能的工作原理,而无需在不同的模板文件之间跳转。这为该功能提供了更清晰、更明显的实现方式。

已知的模板片段实现

片段(以及直接在控制器中渲染它们的能力)似乎是模板库中相对罕见的功能,为使用htmx和其他超媒体导向库时改善开发者体验提供了绝佳机会。

以下是片段概念的一些已知实现:

如果你知道其他实现,请告诉我,以便我将它们添加到此列表中。

</>