extends

这个 extends 标记可用于从另一个模板扩展模板。

注解

和PHP一样,Twig不支持多重继承。所以每次渲染只能有一个extends标记。但是,Twig支持水平方向 reuse .

让我们定义一个基本模板, base.html ,它定义了一个简单的HTML框架文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
    <head>
        {% block head %}
            <link rel="stylesheet" href="style.css"/>
            <title>{% block title %}{% endblock %} - My Webpage</title>
        {% endblock %}
    </head>
    <body>
        <div id="content">{% block content %}{% endblock %}</div>
        <div id="footer">
            {% block footer %}
                &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
            {% endblock %}
        </div>
    </body>
</html>

在这个例子中, block 标记定义了子模板可以填充的四个块。

所有的 block 标记的作用是告诉模板引擎子模板可能会覆盖模板的这些部分。

子模板

子模板可能如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{% extends "base.html" %}

{% block title %}Index{% endblock %}
{% block head %}
    {{ parent() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
        Welcome on my awesome homepage.
    </p>
{% endblock %}

这个 extends 标签是这里的关键。它告诉模板引擎此模板“扩展”另一个模板。当模板系统评估此模板时,它首先找到父模板。extends标记应该是模板中的第一个标记。

注意,因为子模板没有定义 footer 块,使用父模板中的值。

不能定义多个 block 同一模板中具有相同名称的标记。存在这种限制是因为块标记在“两个”方向上工作。也就是说,块标记不仅提供了一个要填充的洞,它还定义了填充 起源 . 如果有两个相似的名字 block 标记在模板中,该模板的父级将不知道要使用哪个块的内容。

如果要多次打印块,则可以使用 block 功能:

1
2
3
<title>{% block title %}{% endblock %}</title>
<h1>{{ block('title') }}</h1>
{% block body %}{% endblock %}

父块

可以使用 parent 功能。这将返回父块的结果:

1
2
3
4
5
{% block sidebar %}
    <h3>Table Of Contents</h3>
    ...
    {{ parent() }}
{% endblock %}

命名块结束标记

Twig允许您将块的名称放在结束标记之后,以提高可读性(名称位于 endblock word必须与块名称匹配):

1
2
3
4
5
{% block sidebar %}
    {% block inner_sidebar %}
        ...
    {% endblock inner_sidebar %}
{% endblock sidebar %}

块嵌套和范围

块可以嵌套用于更复杂的布局。默认情况下,块可以从外部范围访问变量:

1
2
3
{% for item in seq %}
    <li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}

阻止快捷方式

对于内容很少的块,可以使用快捷语法。以下构造也会执行相同的操作:

1
2
3
{% block title %}
    {{ page_title|title }}
{% endblock %}
1
{% block title page_title|title %}

动态继承

Twig通过使用变量作为基模板来支持动态继承:

1
{% extends some_var %}

如果变量的计算结果为 \Twig\Template 或A \Twig\TemplateWrapper 实例,Twig将使用它作为父模板:

// {% extends layout %}

$layout = $twig->load('some_layout_template.twig');

$twig->display('template.twig', ['layout' => $layout]);

您还可以提供检查是否存在的模板列表。存在的第一个模板将用作父模板:

1
{% extends ['layout.html', 'base_layout.html'] %}

有条件继承

由于父对象的模板名称可以是任何有效的Twig表达式,因此可以将继承机制设为条件:

1
{% extends standalone ? "minimum.html" : "base.html" %}

在本例中,模板将扩展“最小值.html“布局模板如果 standalone 变量的计算结果为 true ,以及“基本.html“否则。

积木是如何工作的?

块提供了一种方法来更改模板的某个部分的呈现方式,但它不会以任何方式干扰其周围的逻辑。

让我们用下面的例子来说明块是如何工作的,更重要的是,它是如何不工作的:

1
2
3
4
5
6
7
{# base.twig #}
{% for post in posts %}
    {% block post %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.body }}</p>
    {% endblock %}
{% endfor %}

如果渲染此模板,无论是否使用 block 标签。这个 block 里面 for 循环只是使其可由子模板重写的一种方法:

1
2
3
4
5
6
7
8
9
{# child.twig #}
{% extends "base.twig" %}

{% block post %}
    <article>
        <header>{{ post.title }}</header>
        <section>{{ post.text }}</section>
    </article>
{% endblock %}

现在,当呈现子模板时,循环将使用在子模板中定义的块,而不是在基模板中定义的块;然后执行的模板将等效于以下模板:

1
2
3
4
5
6
{% for post in posts %}
    <article>
        <header>{{ post.title }}</header>
        <section>{{ post.text }}</section>
    </article>
{% endfor %}

让我们再举一个例子:包含在 if 声明:

1
2
3
4
5
6
7
{% if posts is empty %}
    {% block head %}
        {{ parent() }}

        <meta name="robots" content="noindex, follow">
    {% endblock head %}
{% endif %}

与您可能认为的相反,此模板没有条件地定义块;它只是使子模板重写条件时将呈现的内容的输出 true .

如果要有条件地显示输出,请改用以下命令:

1
2
3
4
5
6
7
{% block head %}
    {{ parent() }}

    {% if posts is empty %}
        <meta name="robots" content="noindex, follow">
    {% endif %}
{% endblock head %}

参见

block, block, parent, use