如何在模板中引用和重写基础母版模板(extends)以统一显示风格?

在 AnQiCMS 的世界里,构建一个外观统一、易于管理且高效更新的网站,是每个内容运营者和开发者的共同追求。设想一下,如果网站的每个页面都需要单独设计头部、底部、侧边栏,那么当需要修改Logo、导航菜单或者版权信息时,工作量将是巨大的。幸运的是,AnQiCMS 巧妙地利用了模板继承机制,让我们能够轻松实现显示风格的统一,同时保持内容的灵活更新。

这就像是为你的网站设计了一套精美的“母版”——一个包含所有公共元素和基本布局的骨架。然后,你只需在这个骨架上填充每个页面独有的内容,就能确保整个网站看起来协调一致。AnQiCMS 采用类似 Django 模板引擎的语法,其中的 extendsblock 标签正是实现这一魔法的关键。

搭建你的网站“母版”:extends 的基石

首先,我们需要创建一个基础的母版模板,通常我们会将其命名为 base.html,并放置在你的模板目录(/template/你的模板目录/)下。这个 base.html 文件将承载网站所有页面的共同结构,比如 HTML 的基本骨架、引入的 CSS 样式、JavaScript 脚本、Logo、主导航、页脚版权信息等等。

在这个母版中,你需要定义一些“插槽”,这些插槽就是将来子页面可以填充或重写内容的区域。我们使用 block 标签来定义这些插槽。

举个例子,一个简化的 base.html 可能看起来像这样:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    {# 这里定义页面的标题,子模板可以重写 #}
    {% block title %}
        <title>{% system with name="SiteName" %} - 您的网站标题</title>
    {% endblock %}
    <meta name="keywords" content="{% tdk with name="Keywords" %}">
    <meta name="description" content="{% tdk with name="Description" %}">
    
    {# 引入全局CSS样式 #}
    <link rel="stylesheet" href="{% system with name="TemplateUrl" %}/css/style.css">
    {% block head_extra %}{# 预留给子模板添加额外head内容 #}{% endblock %}
</head>
<body>
    <header class="main-header">
        <div class="logo">
            <a href="{% system with name="BaseUrl" %}">
                <img src="{% system with name="SiteLogo" %}" alt="{% system with name="SiteName" %}">
            </a>
        </div>
        <nav class="main-nav">
            {# 主导航通常放在这里 #}
            {% navList navs %}
            <ul>
                {%- for item in navs %}
                    <li class="{% if item.IsCurrent %}active{% endif %}">
                        <a href="{{ item.Link }}">{{item.Title}}</a>
                        {%- if item.NavList %}
                        <dl>
                            {%- for inner in item.NavList %}
                                <dd><a href="{{ inner.Link }}">{{inner.Title}}</a></dd>
                            {% endfor %}
                        </dl>
                        {% endif %}
                    </li>
                {% endfor %}
            </ul>
            {% endnavList %}
        </nav>
    </header>

    <div class="main-content-wrapper">
        <aside class="sidebar">
            {% block sidebar %}{# 侧边栏内容 #}{% endblock %}
        </aside>
        <main class="page-content">
            {# 这是核心内容区域,每个子页面都会重写这里 #}
            {% block content %}
                <p>这里是母版默认内容,如果子模板不重写,就会显示。</p>
            {% endblock %}
        </main>
    </div>

    <footer class="main-footer">
        <p>{% system with name="SiteCopyright" %}</p>
        <p><a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">{% system with name="SiteIcp" %}</a></p>
    </footer>

    {# 引入全局JS脚本 #}
    <script src="{% system with name="TemplateUrl" %}/js/main.js"></script>
    {% block body_extra %}{# 预留给子模板添加额外body末尾内容 #}{% endblock %}
</body>
</html>

可以看到,base.html 定义了页面的整体布局,并且通过 {% block title %}{% block sidebar %}{% block content %} 等标签,为不同的区域预留了可重写的位置。即使子模板不重写这些 block,它们也会显示 base.html 中定义的默认内容。

子页面:引用母版与重写内容

现在,我们有了网站的“母版”。接下来,当你要创建像首页、文章详情页、产品列表页这样的具体页面时,就不需要重复编写头部和底部了,只需引用这个 base.html,然后重写你需要改变的 block 区域。

引用母版

在你的子模板文件(例如 index.htmlarchive/detail.htmlcategory/list.html)中,你需要做的第一件事就是使用 extends 标签来声明它继承自哪个母版。

非常重要的一点是:{% extends 'base.html' %} 必须是子模板文件的第一行代码。 模板引擎需要首先知道这个文件是基于哪个母版构建的,才能正确解析后续的内容。

重写内容

extends 声明之后,你就可以使用与母版中相同的 block 标签名称来重写该区域的内容了。

比如,针对网站的首页 index.html,你可能希望有自定义的标题和独特的首页内容,但保留公共的头部、底部和侧边栏。你可以这样编写 index.html

{# 必须是文件的第一行 #}
{% extends 'base.html' %}

{# 重写title block,定义首页标题 #}
{% block title %}
    <title>首页 - {% system with name="SiteName" %}</title>
{% endblock %}

{# 重写content block,放置首页特有的内容 #}
{% block content %}
    <h2>欢迎来到我们的网站首页!</h2>
    <p>这里是首页独有的内容,包括精选文章、推荐产品等。</p>
    
    {# 可以在这里引入其他模板片段,例如最新的文章列表 #}
    {% include 'partial/latest_articles.html' %}
{% endblock %}

{# 如果首页需要额外的脚本,可以重写body_extra block #}
{% block body_extra %}
    <script src="{% system with name="TemplateUrl" %}/js/index_specific.js"></script>
{% endblock %}

在这个 index.html 中,我们只重写了 titlecontent 这两个 block。对于 head_extrasidebarmain-headermain-footer 等区域,由于没有重写对应的 block,模板引擎会自动使用 base.html 中定义的内容。这样,我们就实现了页面的统一风格,同时又保证了内容的灵活性。

实践:统一风格与局部创新

模板继承的强大之处在于它的分层思想。你可以为不同类型的内容(如文章详情、产品列表)创建不同的“二级母版”,这些二级母版再继承自 base.html。例如,你可以有一个 article_base.html 来定义所有文章页面的通用布局(比如固定侧边栏、评论区结构等),然后具体的文章详情页再继承 article_base.html

在使用继承的时候,有一些小技巧可以帮助我们更好地组织模板:

  • 将公共头部和底部放在 base.html 中。 这是最基本的统一,确保所有页面都有相同的导航和品牌信息。
  • 将可能变动的区域定义为 block 哪怕现在看起来不会变动,预留 block 也是一个好习惯,以便未来扩展。
  • 对于小的、可复用的组件,使用 include 标签。 例如,一个“最新评论”的模块,可以在 sidebar block 中使用 {% include 'partial/latest_comments.html' %} 来引入。这使得代码更加模块化,便于维护。
  • 不要过度嵌套。 虽然 AnQiCMS 支持多级继承,但过深的继承层级可能会增加