在安企CMS的模板开发中,我们常常会遇到需要重复使用的HTML代码片段或显示逻辑。如果每次都复制粘贴,不仅会增加代码量,降低开发效率,更会在后期维护时带来诸多不便。为了解决这个问题,安企CMS的模板引擎提供了强大的宏函数(Macro)功能,它能帮助我们实现显示逻辑的复用,让模板代码更加简洁、高效。

什么是模板宏函数?

宏函数可以理解为模板中的“自定义函数”。它允许我们将一段常用的HTML结构或显示逻辑封装起来,定义一组接收参数,然后在模板的任何地方多次调用。这样,当我们需要在不同位置展示相同结构的元素时,只需调用宏函数并传入不同的数据,而无需重复编写相同的代码。这大大提升了模板的可维护性和开发效率。

如何定义一个宏函数?

在安企CMS的模板中定义宏函数非常直观,它采用类似Python Django模板引擎的语法。一个宏函数以 {% macro 宏函数名(参数列表) %} 开始,以 {% endmacro %} 结束。参数列表用于接收宏函数运行时所需的数据,它们就像普通函数的参数一样。

让我们来看一个实际的例子。假设我们经常需要在页面上展示一个文章卡片,包含文章标题、链接和简介。如果每次都写一遍这部分HTML,会显得非常冗余。我们可以定义一个 article_card 宏函数来封装它:

{# 定义一个名为 'article_card' 的宏函数,接收 'archive' 作为参数 #}
{% macro article_card(archive) %}
<div class="article-card">
    <a href="{{ archive.Link }}" class="card-link">
        <h3 class="card-title">{{ archive.Title }}</h3>
    </a>
    <p class="card-description">{{ archive.Description|truncatechars:100 }}</p>
    <div class="card-meta">
        <span>发布日期: {{ stampToDate(archive.CreatedTime, "2006-01-02") }}</span>
        <span>浏览量: {{ archive.Views }}</span>
    </div>
</div>
{% endmacro %}

在这个例子中,article_card 宏函数接收一个名为 archive 的参数,这个参数预期是一个文章对象,包含 LinkTitleDescriptionCreatedTimeViews 等属性。在宏函数内部,我们使用这些属性来构建文章卡片的HTML结构。

如何使用宏函数?

定义好宏函数后,就可以在模板中像调用普通函数一样使用它。调用宏函数时,需要使用双花括号 {{ }} 包裹,并传入宏函数定义的参数。

继续上面的例子,如果我们有一个文章列表 archives,现在就可以在 for 循环中轻松地调用 article_card 宏函数来渲染每一个文章卡片:

{# 假设 archives 是通过 archiveList 标签获取到的文章列表 #}
<div class="article-list">
    {% for item in archives %}
        {# 调用 article_card 宏函数,并将当前循环的 item 传入作为参数 #}
        {{ article_card(item) }}
    {% endfor %}
</div>

通过这种方式,无论文章列表有多少项,我们都不需要重复编写文章卡片的HTML结构,只需要一次性定义好宏函数,并在需要的地方调用即可,代码量显著减少,维护起来也更加方便。

组织宏函数:将它们保存在独立文件中

随着项目复杂度的增加,宏函数可能会越来越多,将它们全部定义在一个主模板文件中会使文件变得臃肿。安企CMS模板引擎支持将宏函数定义在独立的 .html 文件中,并按需导入使用,这有助于保持代码的模块化和整洁。

你可以创建一个专门的宏函数文件,例如 macro_helpers.html,并将所有通用的宏函数定义在其中:

{# macro_helpers.html 文件内容 #}
{% macro article_card(archive) %}
    <div class="article-card">
        <a href="{{ archive.Link }}" class="card-link">
            <h3 class="card-title">{{ archive.Title }}</h3>
        </a>
        <p class="card-description">{{ archive.Description|truncatechars:100 }}</p>
        <div class="card-meta">
            <span>发布日期: {{ stampToDate(archive.CreatedTime, "2006-01-02") }}</span>
            <span>浏览量: {{ archive.Views }}</span>
        </div>
    </div>
{% endmacro %}

{% macro button_link(text, url, css_class) %}
    <a href="{{ url }}" class="btn {{ css_class|default:"btn-default" }}">{{ text }}</a>
{% endmacro %}

然后,在任何需要使用这些宏函数的主模板文件中,通过 {% import "文件路径" as 别名 %} 标签来导入:

{# index.html 或其他主模板文件内容 #}
{# 从 "partial/macro_helpers.html" 导入宏函数,并赋予别名 "helpers" #}
{% import "partial/macro_helpers.html" as helpers %}

<div class="main-content">
    <h2>最新文章</h2>
    <div class="article-list">
        {% for item in latest_archives %}
            {{ helpers.article_card(item) }} {# 通过别名调用宏函数 #}
        {% endfor %}
    </div>

    <div class="call-to-action">
        {# 调用另一个导入的宏函数 #}
        {{ helpers.button_link("查看更多文章", "/archives", "btn-primary") }}
    </div>
</div>

通过 as helpers 赋予别名后,我们可以通过 helpers.宏函数名 的形式来调用宏函数,避免命名冲突,并提高代码的可读性。你也可以直接导入宏函数名,或者导入多个宏函数并给其中一些赋予别名。

宏函数与 Include 标签的异同

安企CMS模板中除了宏函数,还有一个 include 标签也能实现代码复用。它们之间有一些重要的区别:

  • 作用域(变量访问):这是最主要的区别。

    • 宏函数(Macro):具有独立的变量作用域。它只能访问作为参数明确传递给它的变量,而不能直接访问调用它的父模板中的其他变量。这使得宏函数更加独立和可预测,是构建纯粹、可复用组件的理想选择。
    • Include 标签:会继承调用它的父模板的所有变量上下文。这意味着在被 include 的文件中,你可以直接使用父模板中定义的任何变量。这适用于将页面布局(如页眉、页脚、侧边栏)拆分成小块,这些小块通常需要访问全局或当前页面的数据。
  • 使用场景

    • 宏函数:适用于那些逻辑相对独立、自包含的UI组件,如产品卡片、评论项、表单输入框、分页器按钮等,它们需要接收特定数据并按特定格式显示。
    • Include 标签:适用于页面结构中较大的、依赖于整个页面上下文的部分,例如网站的通用头部、底部、导航菜单或侧边栏,这些部分可能需要引用网站名称、当前用户信息等。

简而言之,当你的代码片段需要高度独立、只通过传入参数来渲染时,选择宏函数;当你的代码片段需要访问父模板的整个数据环境时,选择 include 标签。

总结

安企CMS的宏函数功能是模板开发中一项非常实用的技巧,它能有效减少冗余代码,提升开发效率和模板的可维护性。通过合理地定义、组织和使用宏函数,我们可以构建出结构清晰、易于扩展的网站模板,让内容展示更加灵活和高效。


常见问题 (FAQ)

  1. 宏函数可以访问当前模板的全局变量吗? 不可以。宏函数拥有独立的作用域,它只能访问作为参数明确传递给它的变量。如果需要访问全局变量,你需要将这些全局变量作为参数传递给宏函数。这是一个重要的设计原则,它确保了宏函数的独立性和可预测性。

  2. 我能在一个宏函数中调用另一个宏函数吗? 当然可以。你可以像调用普通宏函数一样,在一个宏函数内部调用其他已经定义或导入的宏函数。这有助于构建更复杂的、层次化的可复用组件。但需要注意避免循环调用,以免造成无限递归。

  3. 如果我的宏函数文件存放在 template 目录下的 macros 文件夹中,应该如何导入? 如果你的宏函数文件位于 /template/default/partial/macros/my_macros.html(假设你的模板包名为 default),那么在其他模板中导入时,路径应该相对于模板根目录 /template/default/ 来写。例如:{% import "partial/macros/my_macros.html" as my_tools %}。请确保路径与实际文件位置