extends
extends
标签可以用于从另一个模板扩展一个模板。
注意
与 PHP 类似,Twig 不支持多重继承。因此,每次渲染只能调用一个 extends 标签。但是,Twig 支持水平重用。
让我们定义一个基础模板,base.html.twig
,它定义了一个简单的 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 %}
© Copyright 2011 by <a href="https://example.com/">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.twig" %}
{% 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
单词后的名称必须与块名称匹配)
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
或 \Twig\TemplateWrapper
实例,Twig 将使用它作为父模板
1 2 3 4 5
// {% extends layout %}
$layout = $twig->load('some_layout_template.html.twig');
$twig->display('template.html.twig', ['layout' => $layout]);
您还可以提供要检查是否存在的模板列表。第一个存在的模板将用作父模板
1
{% extends ['layout.html.twig', 'base_layout.html.twig'] %}
条件继承
由于父模板的模板名称可以是任何有效的 Twig 表达式,因此可以使继承机制具有条件性
1
{% extends standalone ? "minimum.html.twig" : "base.html.twig" %}
在此示例中,如果 standalone
变量评估为 true
,则模板将扩展 “minimum.html.twig” 布局模板,否则扩展 “base.html.twig”。
块是如何工作的?
块提供了一种更改模板特定部分呈现方式的方法,但它不会以任何方式干扰其周围的逻辑。
让我们看下面的示例,以说明块的工作原理,更重要的是,它如何不工作
1 2 3 4 5 6 7
{# base.html.twig #}
{% for post in posts %}
{% block post %}
<h1>{{ post.title }}</h1>
<p>{{ post.body }}</p>
{% endblock %}
{% endfor %}
如果渲染此模板,则无论有无 block
标签,结果都完全相同。for
循环内的 block
只是使其可被子模板覆盖的一种方式
1 2 3 4 5 6 7 8 9
{# child.html.twig #}
{% extends "base.html.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 %}