模板入门
模板是定义输出文件结构或布局的文本文件,其中包含占位符,用于表示模板渲染时(在 Express 中,模板被称为视图)数据将被插入的位置。
Express 模板选择
Express 可以与许多不同的模板渲染引擎一起使用。在本教程中,我们使用 Pug(以前称为 Jade)作为模板。它是最流行的 Node 模板语言,自称是一种“干净、对空白敏感的 HTML 编写语法,深受 Haml 影响”。
不同的模板语言使用不同的方法来定义布局和标记数据占位符——有些使用 HTML 定义布局,而另一些则使用可以转换成 HTML 的不同标记格式。Pug 属于第二种;它使用 HTML 的一种表示形式,其中每行的第一个词通常代表一个 HTML 元素,后续行的缩进用于表示嵌套。其结果是一个直接转换为 HTML 的页面定义,但更简洁,并且可以说更易于阅读。
注意:使用 Pug 的一个缺点是它对缩进和空白敏感(如果你在错误的地方添加额外的空格,你可能会得到一个无用的错误代码)。然而,一旦你的模板就位,它们就非常容易阅读和维护。
模板配置
当我们在创建骨架网站时,LocalLibrary 被配置为使用 Pug。你应该会在网站的 package.json 文件中看到 pug 模块作为依赖项包含在内,以及在 app.js 文件中看到以下配置设置。这些设置告诉我们正在使用 pug 作为视图引擎,并且 Express 应该在 /views 子目录中搜索模板。
// View engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
如果你查看 views 目录,你会看到项目默认视图的 .pug 文件。这些文件包括主页视图 (index.pug) 和我们稍后需要用自己的内容替换的基础模板 (layout.pug)。
/express-locallibrary-tutorial # the project root
/views
error.pug
index.pug
layout.pug
模板语法
下面的示例模板文件展示了 Pug 许多最有用的功能。
首先要注意的是,该文件映射了典型 HTML 文件的结构,每行(几乎)的第一个词都是一个 HTML 元素,并且缩进用于表示嵌套元素。例如,body 元素位于 html 元素内部,段落元素 (p) 位于 body 元素内部,依此类推。非嵌套元素(例如,单独的段落)位于单独的行上。
doctype html
html(lang="en")
head
title= title
script(type='text/javascript').
body
h1= title
p This is a line with #[em some emphasis] and #[strong strong text] markup.
p This line has un-escaped data: !{'<em> is emphasized</em>'} and escaped data: #{'<em> is not emphasized</em>'}.
| This line follows on.
p= 'Evaluated and <em>escaped expression</em>:' + title
<!-- You can add HTML comments directly -->
// You can add single line JavaScript comments and they are generated to HTML comments
//- Introducing a single line JavaScript comment with "//-" ensures the comment isn't rendered to HTML
p A line with a link
a(href='/catalog/authors') Some link text
| and some extra text.
#container.col
if title
p A variable named "title" exists.
else
p A variable named "title" does not exist.
p.
Pug is a terse and simple template language with a
strong focus on performance and powerful features.
h2 Generate a list
ul
each val in [1, 2, 3, 4, 5]
li= val
元素属性在其关联元素后的括号中定义。在括号内,属性以逗号或空格分隔的属性名称和属性值对的列表形式定义,例如
script(type='text/javascript'),link(rel='stylesheet', href='/stylesheets/style.css')meta(name='viewport' content='width=device-width initial-scale=1')
所有属性的值都经过转义(例如,> 这样的字符被转换为其 HTML 代码等效项,例如 >),以防止 JavaScript 注入或跨站脚本攻击。
如果标签后跟等号,则后续文本将被视为 JavaScript 表达式。因此,例如,在下面的第一行中,h1 标签的内容将是变量 title(在文件中定义或从 Express 传递到模板中)。在第二行中,段落内容是与 title 变量连接的文本字符串。在这两种情况下,默认行为都是转义该行。
h1= title
p= 'Evaluated and <em>escaped expression</em>:' + title
注意:在 Pug 模板中,如果一个变量被使用但没有从你的 Express 代码中传入(或在本地定义),那么它就是“未定义的”。如果你在没有传入 title 变量的情况下使用此模板,则会创建标签,但它们将包含一个空字符串。如果你在条件语句中使用未定义变量,则它们会评估为 false。其他模板语言可能要求模板中使用的变量必须被定义。
如果标签后没有等号,则内容被视为纯文本。在纯文本中,你可以分别使用 #{} 和 !{} 语法插入转义和非转义数据,如下所示。你还可以在纯文本中添加原始 HTML。
p This is a line with #[em some emphasis] and #[strong strong text] markup.
p This line has an un-escaped string: !{'<em> is emphasized</em>'}, an escaped string: #{'<em> is not emphasized</em>'}, and escaped variables: #{title}.
注意:你几乎总是希望转义来自用户的数据(通过 #{} 语法)。可以信任的数据(例如,生成的记录计数等)可以在不转义值的情况下显示。
你可以在行首使用管道字符('|')来表示“纯文本”。例如,下面显示的额外文本将显示在与前一个锚点相同的行上,但不会被链接。
a(href='http://someurl/') Link text
| Plain text
Pug 允许你使用 if、else、else if 和 unless 执行条件操作——例如
if title
p A variable named "title" exists
else
p A variable named "title" does not exist
你还可以使用 each-in 或 while 语法执行循环/迭代操作。在下面的代码片段中,我们循环遍历一个数组以显示变量列表(请注意下面使用 'li=' 将“val”评估为变量。你迭代的值也可以作为变量传递到模板中!
ul
each val in [1, 2, 3, 4, 5]
li= val
该语法还支持注释(可以渲染在输出中,也可以不渲染——由你选择)、混合(用于创建可重用代码块)、case 语句和许多其他功能。有关更详细的信息,请参阅 Pug 文档。
扩展模板
在一个网站中,所有页面通常具有共同的结构,包括用于头部、页脚、导航等的标准 HTML 标记。Pug 不会强制开发人员在每个页面中重复这些“样板”代码,而是允许你声明一个基础模板,然后对其进行扩展,只替换每个特定页面中不同的部分。
例如,在我们的骨架项目中创建的基础模板 layout.pug 如下所示
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content
block 标签用于标记在派生模板中可能被替换的内容部分(如果块未重新定义,则使用其在基类中的实现)。
默认的 index.pug(为我们的骨架项目创建)展示了我们如何覆盖基础模板。extends 标签标识要使用的基础模板,然后我们使用 block section_name 来指示我们将覆盖的部分的新内容。
extends layout
block content
h1= title
p Welcome to #{title}
后续步骤
- 返回 Express 教程第 5 部分:显示图书馆数据。
- 继续阅读第 5 部分的下一子文章:LocalLibrary 基础模板。