SitePoint Premium gives you an entire collection of books covering developer essentials like Pug, Gulp, Git and more. Join now.
SitePoint Premium为您提供了一整套书籍,涵盖了Pug,Gulp,Git等开发人员的必备知识。 现在加入 。
As web designers or developers, we likely all have to write our fair share of HTML. And while this is not the most difficult task, it can often feel a little boring or repetitive. HTML is also static, which means that if you want to display dynamic data (fetched from an API, for example), you invariably end up with a mishmash of HTML stings inside JavaScript. This can be a nightmare to debug and to maintain.
作为网页设计师或开发人员,我们可能都必须编写我们应有HTML。 尽管这不是最困难的任务,但它通常会感到有些无聊或重复。 HTML也是静态的,这意味着,如果要显示动态数据(例如,从API中获取),则不可避免地会在JavaScript中产生大量HTML字符串。 这可能是调试和维护的噩梦。
This is where Pug comes in. Pug is a template engine for Node and for the browser. It compiles to HTML and has a simplified syntax, which can make you more productive and your code more readable. Pug makes it easy both to write reusable HTML, as well as to render data pulled from a database or API.
这是Pug进入的地方。Pug是Node和浏览器的模板引擎。 它可以编译为HTML并具有简化的语法,从而可以提高工作效率并提高代码的可读性。 Pug使编写可重用HTML以及呈现从数据库或API提取的数据变得容易。
In this guide, I’ll demonstrate how to get up and running with Pug. We’ll start by installing it from npm, go over its basic syntax and then look at several examples of using JavaScript in Pug. Finally, we’ll explore a couple of Pug’s more advanced features by building a simple Node/Express project which uses Pug as its template engine.
在本指南中,我将演示如何使用Pug启动和运行。 我们将从npm安装它开始,介绍其基本语法,然后看几个在Pug中使用JavaScript的示例。 最后,我们将通过构建一个简单的Node / Express项目(使用Pug作为其模板引擎)来探索Pug的一些更高级的功能。
Before we start looking at Pug, let’s take a second to understand the concepts involved.
在开始研究Pug之前,让我们花点时间了解其中涉及的概念。
A template engine is a program which is responsible for compiling a template (that can be written using any one of a number of languages) into HTML. The template engine will normally receive data from an external source, which it will inject into the template it’s compiling. This is illustrated by the following diagram.
模板引擎是负责将模板(可以使用多种语言中的任何一种编写)编译为HTML的程序。 模板引擎通常会从外部来源接收数据,并将其注入正在编译的模板中。 下图说明了这一点。
Credit: Dreftymac, 图片来源:Dreftymac, TempEngWeb016, TempEngWeb016 , CC BY-SA 3.0 CC BY-SA 3.0This approach allows you to reuse static web page elements, while defining dynamic elements based on your data. It also facilitates a separation of concerns, keeping your application logic isolated from your display logic.
这种方法使您可以重用静态网页元素,同时根据数据定义动态元素。 它还有利于分离关注点,使您的应用程序逻辑与显示逻辑保持隔离。
You’re more likely to benefit from a template engine if your site or web application is data driven — such as a staff directory for administering employees, a web store that lists various products for users to buy, or a site with dynamic search functionality.
如果您的站点或Web应用程序是数据驱动的,则您更有可能从模板引擎中受益-例如,用于管理员工的人员目录,列出供用户购买的各种产品的Web商店或具有动态搜索功能的站点。
You won’t need a template engine if you’re fetching a small amount of data from an API (in which case you can just use JavaScript’s native template strings), or if you’re making a small static site.
如果您要从API提取少量数据(在这种情况下,您只能使用JavaScript的本机模板字符串 ),或者您要建立一个小型静态网站,则不需要模板引擎。
It’s also worth noting that Pug used to be called Jade until it was forced to change its name due to a trademark claim in 2015. The name change took effect with version 2.0.
还要指出的是,Pug在2015年因商标主张而被迫更改名称之前曾经被称为Jade。名称更改从2.0版开始生效。
There’s still a lot of Jade-related material available online. And while some of it’s probably still quite valid, the fact that the name change coincided with a major version bump means that Pug’s syntax has several differences, deprecations, and removals compared to its predecessor. These are documented here.
在线上仍然有很多与玉有关的资料。 虽然其中一些可能仍然很有效,但名称更改与主要版本颠簸同时发生的事实意味着,Pug的语法与其前身相比具有若干区别,弃用和删除。 这些都记录在这里 。
If you’re interested in finding out more, you can read the original name change announcement in this GitHub issue. Otherwise, just be sure to add the word “template” to your Pug-related Google searches to avoid the results being full of pooches.
如果您想了解更多信息,可以阅读本GitHub问题中的原始名称更改公告。 否则,只需确保在与Pug相关的Google搜索中添加“模板”一词即可避免搜索结果充满歧义。
Before we can get to writing some Pug, we’ll need to install Node, npm (which comes bundled with Node) and the pug-cli package.
在开始编写一些Pug之前,我们需要安装Node,npm(与Node捆绑在一起)和pug-cli软件包 。
There’s a couple options for installing Node/npm. Either head on over to the project’s home page and download the correct binaries for your system, or use a version manager such as nvm. I would recommend using a version manager where possible, as this will allow you to install different Node versions and switch between them at will. It will also negate a bunch of potential permissions errors.
有两个安装Node / npm的选项。 转到项目的主页并为您的系统下载正确的二进制文件,或者使用版本管理器(例如nvm) 。 我建议尽可能使用版本管理器,因为这将允许您安装不同的Node版本并在它们之间随意切换。 它还将消除一堆潜在的权限错误。
You can check out our tutorial “Installing Multiple Versions of Node.js Using nvm” for a more in-depth guide.
您可以查看我们的教程“ 使用nvm安装多个版本的Node.js ”以获取更深入的指导。
Once Node and npm are installed on your system, you can install the pug-cli package like so:
一旦在系统上安装了Node和npm,就可以像下面这样安装pug-cli软件包:
npm i -g pug-cliYou can check that the install process ran correctly by typing pug --version into a terminal. This will output the version of Pug and the version of the CLI that you have installed.
您可以通过在终端中键入pug --version来检查安装过程是否正确运行。 这将输出Pug的版本和已安装的CLI的版本。
At the time of writing, this was as follows:
在撰写本文时,内容如下:
$ pug --version pug version: 2.0.3 pug-cli version: 1.0.0-alpha6If your editor doesn’t offer syntax highlighting for Pug, it’d be a good idea to look for an extension to add this functionality.
如果您的编辑器不提供Pug的语法突出显示功能,那么最好找一个扩展来添加此功能。
I’m currently using Sublime Text 3 and, out of the box, this is what a .pug file looks like:
我目前正在使用Sublime Text 3, .pug文件的外观如下:
To remedy this, one can install the Sublime Pug package:
为了解决这个问题,可以安装Sublime Pug软件包 :
Syntax highlighting will make it much easier to work with Pug files, especially those of any length.
突出显示语法将使处理Pug文件(尤其是任何长度的文件)更加容易。
If you’d like to follow along with the simpler examples in this tutorial, you can also run them in various online code playgrounds.
如果您想按照本教程中的简单示例进行操作,也可以在各种在线代码游乐场中运行它们。
CodePen, for example, has Pug support baked right in. Simply create a new pen, then select Settings > HTML and choose Pug as your preprocessor. This will allow you to enter Pug code into the HTML pane and see the result appear in real time.
例如, CodePen已立即支持Pug。只需创建一个新笔,然后选择“设置” >“ HTML ” ,然后选择Pug作为预处理器。 这将允许您在HTML窗格中输入Pug代码,并实时看到结果。
As an added bonus, you can click on the down arrow in the HTML pane and select View Compiled HTML to see the markup that Pug has generated.
另外,您可以单击HTML窗格中的向下箭头,然后选择“ 查看编译HTML”以查看Pug生成的标记。
Now that we’ve got Pug installed, let’s try it out. Create a new directory named pug-examples and change into it. Then create a further directory called html and a file called index.pug:
现在我们已经安装了Pug,让我们尝试一下。 创建一个名为pug-examples的新目录并将其更改。 然后创建另一个名为html目录和一个名为index.pug的文件:
mkdir -p pug-examples/html cd pug-examples touch index.pugNote: the touch command is Linux/macOS specific. Windows users would do echo.> index.pug to achieve the same thing.
注意: touch命令特定于Linux / macOS。 Windows用户会执行echo.> index.pug来实现相同的目的。
The way this is going to work is that we’ll write our Pug code in index.pug and have the pug-cli watch this file for changes. When it detects any, it will take the contents of index.pug and render it as HTML in the html directory.
这将起作用的方式是,我们将在index.pug文件index.pug编写我们的Pug代码, index.pug pug-cli监视该文件中的更改。 当检测到任何内容时,它将获取index.pug的内容,并将其呈现为html目录中的html 。
To kick this off, open a terminal in the pug-examples directory and enter this:
要开始此操作,请在pug-examples目录中打开一个终端,然后输入以下内容:
pug -w . -o ./html -PYou should see something like the following:
您应该看到类似以下的内容:
watching index.pug rendered /home/jim/Desktop/pug-examples/html/index.htmlNote: in the above command, the -w option stands for watch, the dot tells Pug to watch everything in the current directory, -o ./html tells Pug to output its HTML in the html directory and the -P option prettifies the output.
注意:在上面的命令中, -w选项代表watch,点告诉Pug观看当前目录中的所有内容, -o ./html告诉Pug在html目录中输出其HTML, -P选项使输出-o ./html 。
Now let’s create the page from the screenshot above (the one complaining about the lack of syntax highlighting). Enter the following into index.pug:
现在,让我们从上面的屏幕截图创建页面(该页面抱怨缺少语法突出显示)。 在index.pug输入以下index.pug :
doctype html html(lang='en') head title Hello, World! body h1 Hello, World! div.remark p Pug rocks!Save pug.index and then inspect the contents of ./html/index.html. You should see the following:
保存pug.index ,然后检查./html/index.html的内容。 您应该看到以下内容:
<!DOCTYPE html> <html lang="en"> <head> <title>Hello, World!</title> </head> <body> <h1>Hello, World!</h1> <div class="remark"> <p>Pug rocks!!</p> </div> </body> </html>Not bad, eh? The Pug CLI has taken our Pug file and rendered it as regular HTML.
还不错吧? Pug CLI已获取我们的Pug文件,并将其呈现为常规HTML。
This example serves to highlight a couple of important points about Pug. Firstly, it is whitespace sensitive, which means that Pug uses indentation to work out which tags are nested inside each other. For example:
此示例旨在突出有关Pug的几个要点。 首先,它对空格敏感 ,这意味着Pug使用缩进来找出哪些标签相互嵌套。 例如:
div.remark p Pug rocks!!The code above produces this:
上面的代码产生了这个:
<div class="remark"> <p>Pug rocks!!</p> </div>Now take this code:
现在使用以下代码:
div.remark p Pug rocks!!This produces the following:
这将产生以下结果:
<div class="remark"></div> <p>Pug rocks!!</p>It doesn’t really matter what level of indentation you use (you can even use tabs if you have to), but it’s highly recommended that you keep the level of indentation consistent. In this article I’ll be using two spaces.
使用哪种缩进级别并不重要(如果需要,甚至可以使用制表符),但是强烈建议您保持一致的缩进级别。 在本文中,我将使用两个空格。
Secondly, Pug doesn’t have any closing tags. This will obviously save you a fair few keystrokes and affords Pug a clean and easy-to-read syntax.
其次, Pug没有任何结束标记 。 显然,这将为您节省一些击键,并为Pug提供一种简洁易懂的语法。
Now that we’ve got a handle on some basic Pug, let’s quickly go over its syntax. If any of this seems confusing, or you’d like to go more in-depth, be sure to consult the project’s excellent documentation.
既然我们已经掌握了一些基本的Pug,现在让我们快速了解一下它的语法。 如果其中任何一个看起来令人困惑,或者您想进一步深入,请确保查阅该项目的出色文档 。
You can use Pug to generate a number of document type declarations.
您可以使用Pug生成许多文档类型声明。
For example doctype html will compile to <!DOCTYPE html>, the standard HTML5 doctype, whereas doctype strict will give us <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">. Pug will do its best to ensure that its output is valid for the document type.
例如doctype html将编译为标准HTML5 doctype <!DOCTYPE html> ,而doctype strict将为我们提供<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 。 Pug将尽力确保其输出对于文档类型有效。
As mentioned, Pug doesn’t have any closing tags and relies on indentation for nesting. This might take a small amount of getting used to, but once you do, it makes for clean and readable code. By way of an example:
如前所述,Pug没有任何结束标记,并且依赖缩进进行嵌套。 这可能需要一点时间来习惯,但是一旦您习惯了,它就会使代码清晰易读。 举个例子:
nav navbar-default div h1 My Website! ul li a Home li a Page 1 li a Page 2 inputThe code above compiles to this:
上面的代码编译为此:
<nav> <div> <h1>My Website!</h1> </div> <ul> <li><a>Home</a></li> <li><a>Page 1</a></li> <li><a>Page 2</a></li> </ul> <input/> </nav>Notice that Pug is smart enough to close any self-closing tags (such as the <input /> element) for us.
请注意,Pug足够聪明,可以为我们关闭任何自动关闭的标签(例如<input />元素)。
Classes and IDs are expressed using a .className and #IDname notation. For example:
类和ID使用.className和#IDname表示法表示。 例如:
nav#navbar-default div.container-fluid h1.navbar-header My Website!Pug also offers us a handy shortcut. If no tag is specified, it will assume a <div> element:
帕格还为我们提供了方便的捷径。 如果未指定标签,它将采用<div>元素:
nav#navbar-default .container-fluid h1.navbar-header My Website!Both of these compile to:
这两个都编译为:
<nav id="navbar-default"> <div class="container-fluid"> <h1 class="navbar-header">My Website!</h1> </div> </nav>Attributes are added using brackets:
使用括号添加属性:
ul li a(href='/') Home li a(href='/page-1') Page 1 li a(href='/page-2') Page 2 input.search( type='text' name='search' placeholder='Enter a search term...' )This results in the following:
结果如下:
<ul> <li><a href="/">Home</a></li> <li><a href="/page-1">Page 1</a></li> <li><a href="/page-2">Page 2</a></li> </ul> <input class="search" type="text" name="search" placeholder="Enter a search term..."/>There’s a lot more to say about attributes. For example, you could use JavaScript to include variables in your attributes, or assign an array of values to an attribute. We’ll get on to using JavaScript in Pug in the next section.
关于属性还有很多要说的。 例如,您可以使用JavaScript在属性中包含变量,或为属性分配值数组。 在下一节中,我们将继续在Pug中使用JavaScript。
Pug provides various methods for adding plain text directly into the rendered HTML.
Pug提供了多种将纯文本直接添加到呈现HTML中的方法。
We’ve already seen how to add plain text inline:
我们已经了解了如何内联添加纯文本:
h1.navbar-header My Website! We can write anything we want here …Another way is to prefix a line with a pipe character (|):
另一种方法是用竖线字符( | )为行添加前缀:
p | You are logged in as | user@example.comThis gives us the following:
这给我们以下内容:
<p> You are logged in as user@example.com </p>When dealing with large blocks of text, you can just ad a dot . right after the tag name, or after the closing parenthesis, if the tag has attributes:
处理大块文字时,您可以仅添加一个点. 如果标签具有属性,则紧接在标签名称之后,或在右括号之后。
p. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.This results in:
结果是:
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </p>Finally, comments can be added like so:
最后,可以像这样添加注释:
// My wonderful navbar nav#navbar-defaultThis comment will be added to the rendered HTML:
此注释将添加到呈现HTML中:
<!-- My wonderful navbar--> <nav id="navbar-default"></nav>You start a comment like so:
您开始这样的评论:
//- My wonderful navbar nav#navbar-defaultWhen you do this, the comment will remain in the Pug file but won’t appear in the HTML.
执行此操作时,注释将保留在Pug文件中,但不会出现在HTML中。
Comments must appear on their own line. Here, the comment will be treated as plain text:
注释必须出现在自己的行上。 在这里,注释将被视为纯文本:
nav#navbar-default // My wonderful navbarMultiline comments are possible, too:
多行注释也是可能的:
// My wonderful navbar It is just so, awesome! nav#navbar-defaultBelow you can find a demo of a Bootstrap-style layout which demonstrates the techniques we’ve discussed so far:
在下面,您可以找到Bootstrap样式的布局演示,该演示演示了到目前为止我们讨论的技术:
See the Pen Basic Pug Demo by SitePoint (@SitePoint) on CodePen.
请参阅CodePen上的SitePoint ( @SitePoint )的Pen Basic Pug演示 。
One of the great things about Pug is the ability to run JavaScript in your templates. This makes it easy to insert variables into our templates, iterate over arrays and objects, conditionally render HTML, and much more.
Pug的一大优点是能够在模板中运行JavaScript。 这样可以很容易地将变量插入模板中,遍历数组和对象,有条件地呈现HTML等。
This is an important distinction to be aware of before using JavaScript in Pug.
这是在Pug中使用JavaScript之前要意识到的重要区别。
Unbuffered code starts with a minus (-). It doesn’t directly add anything to the output, but its values may be used from within Pug:
未缓冲的代码以减号( - )开头。 它不会直接在输出中添加任何内容,但是可以在Pug中使用其值:
- const name = "Jim" //- Now I can refer to a 'name' variable in my Pug codeBuffered code, on the other hand, starts with an equals (=). It evaluates a JavaScript expression and outputs the result.
另一方面, 缓冲的代码以等号( = )开头。 它评估一个JavaScript表达式并输出结果。
p= 'Two to the power of ten is: ' + 2**10The code above compiles to this:
上面的代码编译为此:
<p>Two to the power of ten is: 1024</p>For reasons of security, buffered code is HTML escaped.
出于安全考虑,缓冲的代码是HTML转义的。
p= '<script>alert("Hi")</script>'The code above compiles to this:
上面的代码编译为此:
<p><script>alert("Hi")</script></p>p>String interpolation is the process of replacing one or more placeholders in a template with a corresponding value. As we’ve just seen, buffered input offers one method of doing this. Another is using #{}. Here, Pug will evaluate any code between the curly brackets, escape it, and render it into the template.
字符串插值是将模板中的一个或多个占位符替换为相应值的过程。 正如我们已经看到的,缓冲输入提供了一种执行此操作的方法。 另一个正在使用#{} 。 在这里,Pug将评估大括号之间的所有代码,对其进行转义,并将其渲染到模板中。
- const name = "jim" p Hi #{name}The code above compiles to this:
上面的代码编译为此:
<p>Hi jim</p>As the curly brackets can contain any valid JavaScript expression, this opens up a bunch of possibilities:
由于大括号可以包含任何有效JavaScript表达式,因此开辟了很多可能性:
- const name = "jim" - //- Upcase first letter p Hi #{name.charAt(0).toUpperCase() + name.slice(1)}This compiles to:
编译为:
<p>Hi Jim</p>It’s also possible to render unescaped values into your templates using !{}. But this is not the best idea if the input comes from an untrusted source.
也可以使用!{}将未转义的值呈现到模板中。 但是,如果输入来自不受信任的来源,那么这不是最好的主意。
Note: when you want to assign the value held in a variable to an element’s attribute, you can omit the #{}. For example: img(alt=name).
注意:当您要将变量中包含的值分配给元素的属性时,可以省略#{} 。 例如: img(alt=name) 。
Pug’s each keyword makes it easy to iterate over arrays:
Pug的each关键字使遍历数组变得容易:
- const employees = ['Angela', 'Jim', 'Nilson', 'Simone'] ul each employee in employees li= employeeThis results in the following:
结果如下:
<ul> <li>Angela</li> <li>Jim</li> <li>Nilson</li> <li>Simone</li> </ul>You can also use it to iterate over the keys in an object:
您还可以使用它来遍历对象中的键:
- const employee = { 'First Name': 'James', 'Last Name': 'Hibbard' } ul each value, key in employee li= `${key}: ${value}`This results in:
结果是:
<ul> <li>First Name: James</li> <li>Last Name: Hibbard</li> </ul>Pug also lets you provide an else block that will be executed if the array or object is empty:
Pug还允许您提供一个else块,如果数组或对象为空,则将执行该块:
- const employees = [] ul each employee in employees li= employee else li The company doesn't have any employees. Maybe hire some?Finally, note that you can use for as an alias for each.
最后,请注意,您可以使用for为的别名each 。
Conditionals offer a very handy way of rendering different HTML depending upon the result of a JavaScript expression:
条件提供了一种非常方便的方式来呈现不同HTML,这取决于JavaScript表达式的结果:
- const employee = { firstName: 'James', lastName: 'Hibbard', extn: '12345' } #employee p= `${employee.firstName} ${employee.lastName}` p Extension: if employee.extn =employee.extn else | n/aIn this example, we’re checking whether the employee object has an extn property, then either outputting the value of that property (if it exists), or the text “n/a”.
在此示例中,我们正在检查employee对象是否具有extn属性,然后输出该属性的值(如果存在)或文本“ n / a”。
Below you can find a demo of some of the techniques we’ve discussed in this section. This showcases Pug’s benefits somewhat more than the previous demo, as all we need to do to add further employees is to add further objects to our sitePointEmployees array.
在下面,您可以找到我们在本节中讨论的一些技术的演示。 这展示了Pug的好处比以前的演示要多一些,因为我们需要做的增加更多员工的工作就是在sitePointEmployees数组中添加更多对象。
See the Pen JavaScript in Pug Demo by SitePoint (@SitePoint) on CodePen.
请参阅CodePen上的SitePoint ( @SitePoint )的Pug演示中的Pen JavaScript 。
Now that we have a reasonable idea of Pug’s syntax and how it works, let’s finish off by building a small Express.js app to demonstrate a couple of Pug’s more advanced features.
现在,我们对Pug的语法及其工作原理有了一个合理的了解,让我们最后通过构建一个小型Express.js应用程序来演示Pug的一些更高级的功能。
The code for this example is available on GitHub.
该示例的代码可在GitHub上找到 。
Note: if you’ve not used Express before, no worries. It’s a web framework for Node.js which provides a robust set of features for building web apps. If you’d like to find out more, check out our getting started with Express tutorial.
注意:如果您以前从未使用过Express,则无需担心。 这是Node.js的Web框架,提供了用于构建Web应用程序的一组强大功能。 如果您想了解更多信息,请查看我们的Express入门教程 。
First off, let’s create a new project and install Express:
首先,让我们创建一个新项目并安装Express:
mkdir pug-express cd pug-express npm init -y npm i expressNext create an app.js file in the pug-express folder:
接下来在pug-express文件夹中创建一个app.js文件:
touch app.jsThen add the following:
然后添加以下内容:
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Hello, World!'); }); app.listen(3000, () => { console.log('Listening on port 3000...'); });Here we’re declaring a route (/), which will respond to a GET request with the text “Hello, World!” We can test this in our browsers, by starting the server with node app.js and then visiting http://localhost:3000.
在这里,我们声明一条路由( / ),它将以文本“ Hello,World!”响应GET请求。 我们可以在浏览器中对此进行测试,方法是使用node app.js启动服务器,然后访问http:// localhost:3000 。
If you see something like this, then things have gone to plan:
如果您看到类似这样的信息,那么说明事情已经计划好了:
This Express app won’t do anything too spectacular. We’ll be building a simple staff directory which fetches a list of employees from a database and displays them in a table. For that to happen, we’ll need a database and some data.
这个Express应用程式不会做得太壮观。 我们将构建一个简单的职员目录,该目录将从数据库中获取职员列表并将其显示在表格中。 为此,我们需要一个数据库和一些数据。
However … installing and configuring a database is a little heavy handed for this small example, so I’m going to use a package called json-server. This will allow us to create a db.json file which it will turn into a REST API that we can perform CRUD operations against.
但是…对于这个小例子,安装和配置数据库有点繁琐,因此我将使用一个名为json-server的软件包。 这将使我们能够创建db.json文件,该文件将转换为REST API,我们可以对其执行CRUD操作。
Let’s install it:
让我们安装它:
npm i -g json-serverNow create the aforementioned db.json file in the project’s root:
现在,在项目的根目录中创建上述的db.json文件:
touch db.jsonFinally, we need some JSON to populate it. We’ll use the Random User Generator, which is a free, open-source API for generating random user data. Twenty-five people should do for our example, so head over to https://randomuser.me/api/?results=25 and copy the results into db.json.
最后,我们需要一些JSON来填充它。 我们将使用Random User Generator ,这是一个免费的开源API,用于生成随机用户数据。 我们的示例应由25个人完成,因此请转到https://randomuser.me/api/?results=25然后将结果复制到db.json 。
Finally, start the server in a second terminal window with:
最后,使用以下命令在第二个终端窗口中启动服务器:
json-server --watch db.json -p=3001This will cause json-server to start up on port 3001 and watch our database file for changes.
这将导致json-server在端口3001上启动,并查看我们的数据库文件中的更改。
Express has excellent support for using Pug, so very little configuration is necessary.
Express对使用Pug具有出色的支持,因此几乎不需要任何配置。
First, let’s add Pug to our project:
首先,让我们将Pug添加到我们的项目中:
npm i pugThen in app.js we need to tell Express to use Pug:
然后在app.js我们需要告诉Express使用Pug:
app.set('view engine', 'pug');Next, create a views directory, then in the views directory, add an index.pug file:
接下来,创建一个views目录,然后在views目录中添加一个index.pug文件:
mkdir views touch views/index.pugAdd some content to that file:
向该文件添加一些内容:
doctype html html(lang='en') head title Hello, World! body h1 Hello, World!Then alter app.js like so:
然后像这样修改app.js :
const express = require('express'); const app = express(); app.set('view engine', 'pug'); app.get('/', (req, res) => { res.render('index'); }); app.listen(3000, () => { console.log('Listening on port 3000...'); });Finally, restart the Node server, then refresh your browser and you should see this:
最后,重新启动节点服务器,然后刷新浏览器,您应该看到以下内容:
And that’s it. You’re good to go.
就是这样。 你很好
The next task on the list is to hand some data to the Pug template to display. To do that, we’ll need a method of fetching the data from the json-server. Unfortunately, the fetch API isn’t implemented in Node, so let’s use axios, the popular HTTP client instead:
列表上的下一个任务是将一些数据交给Pug模板进行显示。 为此,我们需要一种从json服务器获取数据的方法。 不幸的是,fetch API并未在Node中实现,因此我们使用流行的HTTP客户端axios代替:
npm i axiosThen alter app.js like so:
然后像这样修改app.js :
const express = require('express'); const axios = require('axios'); const app = express(); app.set('view engine', 'pug'); app.get('/', async (req, res) => { const query = await axios.get('http://localhost:3001/results'); res.render('index', { employees: query.data }); }); app.listen(3000, () => { console.log('Listening on port 3000...'); });There’s a couple of things going on here. We’ve turned our route handler into an async function, so that we can wait for the employee data to be returned from json-server before handing it off to the template.
这里发生了几件事。 我们已经将路由处理程序变成了async函数 ,以便我们可以等待json-server返回员工数据,然后再将其传递给模板。
Then we render the index as before, but this time we pass it an object literal containing all of our data.
然后我们像以前一样渲染索引,但是这次我们将包含所有数据的对象常量传递给它。
Note: you have to restart the Node server every time you make a change to app.js. If this starts to get annoying, check out nodemon, which will do this for you.
注意:每次更改app.js时,都必须重新启动Node服务器。 如果这变得令人讨厌,请查看nodemon ,它将为您完成此操作。
Now for the Pug. Change index.pug to look like the following:
现在给哈巴狗。 将index.pug更改为如下所示:
doctype html html(lang='en') head title Staff Directory link(rel='stylesheet' href='https://cdn.jsdelivr.net/npm/semantic-ui@2.3.3/dist/semantic.min.css') style. table.ui.celled img { display: inline-block; } footer { margin: 35px 0 15px 0; text-align: center } body main#main h1.ui.center.aligned.header Staff Directory .ui.container table.ui.celled.table.center.aligned thead tr th Avatar th First Name th Last Name th Email th Phone th City tbody each employee in employees tr td img.ui.mini.rounded.image(src=employee.picture.thumbnail) td #{employee.name.first} td #{employee.name.last} td #{employee.email} td #{employee.phone} td #{employee.location.city} tfoot tr th(colspan='6') footer p © #{new Date().getFullYear()} My CompanyThere’s hopefully nothing surprising going on here. We’re using semantic-ui-css for some styling, as well as a couple of styles of our own.
希望这里没有令人惊讶的事情。 我们将语义ui-css用于某些样式以及我们自己的几种样式。
Then, in the table body we’re iterating over the array of employees that we are passing in from app.js and outputting their details to a table.
然后,在表主体中,我们遍历从app.js传入的employees数组,并将其详细信息输出到表中。
At the bottom of the page is a footer with our copyright claim and the current year.
页面底部是页脚,其中包含我们的版权声明和当前年份。
If you refresh the page now, you should see this:
如果现在刷新页面,应该看到以下内容:
This is pretty nice already, but to round things off, I’m going to demonstrate how to structure our views to offer maximum flexibility as the project grows.
这已经很不错了,但是为了解决问题,我将演示如何构建我们的视图,以随着项目的发展提供最大的灵活性。
Let’s start off by creating a layout.pug file in the views directory:
让我们从在views目录中创建layout.pug文件开始:
touch views/layout.pugThen add the following:
然后添加以下内容:
doctype html html head title Staff Directory link(rel='stylesheet' href='https://cdn.jsdelivr.net/npm/semantic-ui@2.3.3/dist/semantic.min.css') style. table.ui.celled img { display: inline-block; } footer { margin: 35px 0 15px 0; text-align: center } body main#main h1.ui.center.aligned.header Staff Directory .ui.container block content block footer footer p © #{new Date().getFullYear()} My CompanyWhat we’ve done here is create a layout file than can be extended by other Pug files within our project. When you have a large number of Pug files, this saves a considerable amount of code.
我们在这里所做的是创建一个布局文件,该文件可以由我们项目中的其他Pug文件扩展。 当您有大量的Pug文件时,这可以节省大量代码。
The way this works is that we’ve defined two blocks of content (block content and block footer) that a child template may replace. In the case of the footer block, we’ve also defined some fallback content that will be rendered if the child template doesn’t redefine this block.
运作方式是我们定义了两个内容模板( block content和block footer ),它们可以替换子模板。 对于footer块,我们还定义了一些后备内容,如果子模板未重新定义此块,则将呈现这些内容。
Now we can tell our index.pug file to inherit from our layout:
现在我们可以告诉我们的index.pug文件从我们的布局继承:
extends layout.pug block content table.ui.celled.table.center.aligned thead tr th Avatar th First Name th Last Name th Email th Phone th City tbody each employee in employees tr td img.ui.mini.rounded.image(src=employee.picture.thumbnail) td #{employee.name.first} td #{employee.name.last} td #{employee.email} td #{employee.phone} td #{employee.location.city} tfoot tr th(colspan='6')The result is the same as we had before, but the code now has a better structure.
结果与以前相同,但是代码现在具有更好的结构。
Mixins allow you to create reusable blocks of Pug. We can use this to extract our table row into its own file.
Mixins允许您创建可重复使用的Pug块。 我们可以使用它来将表行提取到其自己的文件中。
Create a folder called mixins in the views folder and in that folder create a file named _tableRow.pug:
在views文件夹中创建一个名为mixins的文件夹,然后在该文件夹中创建一个名为_tableRow.pug的文件:
mkdir views/mixins touch views/mixins/_tableRow.pugMixins are declared using the mixin keyword. They are compiled to functions and can take arguments. Add the following to views/mixins/_tableRow.pug:
使用mixin关键字声明mixin 。 它们被编译为函数并且可以接受参数。 将以下内容添加到views/mixins/_tableRow.pug :
mixin tableRow(employee) tr td img.ui.mini.rounded.image(src=employee.picture.thumbnail) td #{employee.name.first} td #{employee.name.last} td #{employee.email} td #{employee.phone} td #{employee.location.city}Now alter index.pug like so:
现在像这样更改index.pug :
extends layout.pug include mixins/_tableRow block content table.ui.celled.table.center.aligned thead tr th Avatar th First Name th Last Name th Email th Phone th City tbody each employee in employees +tableRow(employee) tfoot tr th(colspan='6')As you can see, we’re importing the mixin at the top of the file. We then call it by prefixing its name with a plus symbol and pass it our employee object to display.
如您所见,我们在文件顶部导入了mixin。 然后,我们通过在名称前加上加号来对其进行调用,并将其传递给我们的employee对象以进行显示。
This is overkill for our little app, but it demonstrates a very useful feature of Pug which allows us to write reusable code.
对于我们的小应用程序来说,这太过分了,但是它展示了Pug的一个非常有用的功能,它允许我们编写可重用的代码。
Well done if you’ve made it this far! We’ve covered a lot of ground in this tutorial. We’ve looked at installing Pug, its basic syntax, its JavaScript support and constructs for iteration and conditional rendering. Finally, we built a fully functioning Express app which pulls data from a remote source and feeds it to a Pug template.
做得好,如果你已经做到了! 在本教程中,我们已经涵盖了很多基础知识。 我们已经研究了安装Pug,其基本语法,其JavaScript支持以及用于迭代和条件渲染的构造。 最后,我们构建了一个功能全面的Express应用程序,该应用程序从远程源中提取数据并将其提供给Pug模板。
There’s still a lot more that Pug can do. I’d encourage you to check out its excellent documentation and to just start using it in your projects. You can also use it with several modern JS frameworks, such as React or Vue, and it has even been ported to several other languages.
哈巴狗还有很多事情可以做。 我鼓励您查看其出色的文档,并开始在您的项目中使用它。 您还可以将其与几种现代JS框架(例如React或Vue)一起使用 ,甚至已经移植到其他几种语言 。
If you’re looking for a challenge, why not try extending the employee directory to add the missing CRUD functionality. And if you get stuck with the syntax, don’t forget that help is always at hand.
如果您正在寻找挑战,为什么不尝试扩展员工目录以添加缺少的CRUD功能。 而且,如果您对语法感到困惑,请不要忘记总是有帮助 。
翻译自: https://www.sitepoint.com/a-beginners-guide-to-pug/
相关资源:哈巴狗404错误页面模板