在 AnQiCMS 的模板设计中,我们经常会遇到需要展示长文本内容的场景,例如文章列表页面的摘要、产品详情的简要介绍等。如果这些长文本内容直接显示,可能会导致页面冗长,影响用户体验和布局美观。因此,对长文本进行截断处理是常见的需求。

然而,当这些长文本内容中包含 HTML 标签时,简单的字符截断可能会带来问题。例如,一个 <p>这是一段<b>重要的</b>文本</p> 这样的内容,如果截断在 <b> 标签中间,就可能导致 HTML 结构被破坏,页面显示异常。这时,我们就需要一种安全的方式来截断包含 HTML 标签的长文本。

AnQiCMS 提供了强大而灵活的模板引擎,其语法类似于 Django 模板。在这个引擎中,我们可以利用内置的过滤器(filters)来优雅地解决这个问题。其中,专门为处理包含 HTML 的文本设计的截断过滤器,能够智能地截断内容,并尽量保持 HTML 标签的完整性,避免页面结构混乱。

认识 HTML 安全截断过滤器

在 AnQiCMS 的模板中,有两组核心的截断过滤器可以帮助我们安全地处理长文本:truncatechars_htmltruncatewords_html。它们与普通的 truncatecharstruncatewords 的主要区别在于,它们是“HTML 敏感”的,会尝试识别并闭合未完成的 HTML 标签,从而避免因截断导致页面渲染错误。

  • truncatechars_html:长度:这个过滤器会按照指定的字符数量来截断文本。它会计算可见字符(不包括 HTML 标签本身的字符),并在截断时尽量确保所有打开的 HTML 标签都被正确闭合。如果内容被截断,通常会在末尾添加“…”。
  • truncatewords_html:单词数:这个过滤器则按照指定的单词数量来截断文本。与按字符截断类似,它同样会关注 HTML 结构的完整性,并在截断时进行必要的标签闭合。

为什么不能直接用 truncatechars 截断 HTML 内容?

普通的 truncatechars 过滤器只是简单地从头开始计算字符,一旦达到指定长度就停止。它不会区分哪些是可见文本,哪些是 HTML 标签,更不会在截断后尝试闭合未完成的标签。这就意味着,如果你用 truncatechars 截断 <b>重要的</b>,可能会得到一个 <b>重要 这样的结果,导致页面上后续的所有文本都变成了粗体,或者其他不可预期的样式问题。而 _html 后缀的过滤器则会避免这种情况。

在 AnQiCMS 模板中应用 HTML 安全截断

我们以常见的文章内容为例,archiveDetail 标签用于获取文档详情,其中的 Content 字段通常包含带有 HTML 格式的文本。

假设我们需要在一个列表页或摘要区域展示文章内容的简短预览,限制为 100 个字符。操作步骤如下:

  1. 获取文档内容: 首先,你需要使用 archiveDetail 标签获取到文章的 Content 字段。为了方便后续操作,我们可以将它赋值给一个变量,例如 articleContent

    {% archiveDetail articleContent with name="Content" %}
    

    或者在 archiveList 循环中,直接使用 item.Content

    {% for item in archives %}
        {# 这里可以直接访问 item.Content #}
    {% endfor %}
    
  2. 应用截断过滤器并确保安全输出: 在 AnQiCMS 模板中,任何包含 HTML 的内容在输出时都应该使用 |safe 过滤器,以防止模板引擎将其中的 HTML 标签转义为纯文本。这对于截断后的 HTML 内容尤为重要,因为我们希望浏览器能正常解析这些标签。

    articleContent 截断为 100 个字符并安全输出:

    {{ articleContent|truncatechars_html:100|safe }}
    

    如果您更倾向于按单词数截断,例如截断为 30 个单词:

    {{ articleContent|truncatewords_html:30|safe }}
    

完整的示例场景:在文章列表页显示 HTML 格式的摘要

假设你的文章列表循环名为 archives,你希望每篇文章都显示一段 150 个字符以内的摘要,并且保留文章中的粗体、链接等基本格式:

”`twig {% archiveList archives with type=“page” limit=“10” %}

{% for item in archives %}
<div class="article-item">
    <h2><a href="{{ item.Link }}">{{ item.Title }}</a></h2>
    <div class="article-meta">
        <span>发布日期: {{ stampToDate(item.CreatedTime, "2006-01-02") }}</span>
        <span>浏览量: {{ item.Views }}</span>
    </div>
    <div class="article-summary">
        {# 安全地截断HTML内容,并使用|safe避免转义 #}
        {{ item.Content|truncatechars_html:150|safe }}
        <a href="{{ item.Link