为了改写 Hexo 模板,学习了 Pug(Jade) ,写一个快速查询手册,方便自己和大家。
本手册不太适合初学者。
Pug 由原来的 Jade 改名为 Pug…

什么是 Pug(Jade) ?

Pug(Jade) 是用来快速构建 HTML 的模板引擎,简单可以理解为用来写 HTML 的。
Pug 的 github Pug 的官网网站

Pug(Jade) 语法

声明语法

1
doctype html/xml/xhtml
除了声明语法之外,Pug(Jade) 每一行的第一个单词会被认为是一个 HTML 标签 Pug(Jade) 依靠缩进判断嵌套关系,像 Python 在 Pug(Jade) 中千万不能空格和 Tab 混合使用,否则无法编译

标签也可以有 id

1
div#container

会被转化成

标签也可以有 class
1
div.user-details

会被转化成

多个 class,多个 id
1
div#foo.bar.baz

会被转换为

语法糖 (便捷语法)

1
2
#foo
.bar

会被转换为

注释

单行注释
1
//      comments

块注释

块注释的写法是在 //</code > 后换行并缩进,之后的多行注释内容保持缩进即可,当不需要注释时取消缩进即可

1
2
3
4
//
first line comment
second line comment
END

不输出的注释 (Pug 文件的注释,不会被生成 HTML 的一部分)

1
2
//-     will not output within markup
p foo

会被转换成

1
<p>foo</p>

条件注释

1
2
3
body
//if IE
a(href='http://www.mozilla.com/en-US/firefox/') Get Firefox

嵌套

默认情况下,每行的第一个单词会被认为是 HTML 标签,第二行缩进的单词是子标签。
另外一种情况为嵌套的行内语法,就是在父标签后跟上 :</code > 和空格之后再跟嵌套子标签。
如果想取消嵌套,只能在下一个和嵌套父标签有相同缩进的标签处退出 (需要特别注意),否则整个程序会一层一层嵌套下去
正确的行内嵌套及取消

1
2
3
4
html
head: title Tag Demo
body
p This is a Tag Demo

错误的行内嵌套及取消
1
2
3
html: head: title Tag Demo
body
p This is a Tag Demo

自封闭标签

HTML 中的自封闭标签,例如 imgmeta</code > 等,在 Pug(Jade) 中自封闭标签后边紧跟圆括号,在括号中填写标签的参数即可。

1
2
img(src="/img.png")
meta(charset="utf-8")

自定义自封闭标签

只需要在标签后加上 /</code > 即可

1
2
customized/
customized(id="customized")/

基本属性

在 Pug(Jade) 中,在一个标签后边紧跟上一对圆括号,在圆括号中使用表达式赋值。

1
a(href="google.com")

还有一种可以添加属性的方法是使用 &attributes 语法操作属性对象
1
p#para&attributes({"A": "a", "B": "b"}) My paragraph.

除此之外还可以定义变量,然后使用标准的 JavaScript 表达式给 Attributes 赋值
1
2
- var x = 1;
body(id=x==1?1:0)

其中,在 Pug(Jade) 中定义变量使用 - 开头,后边跟一个空格,之后是 JavaScript 声明的变量。
如果一个标签有多个属性,使用逗号分隔
1
2
3
4
5
6
7
input(id="username",type="text",name="username")
// 甚至可以分开多行来写
input(
id="username",
type="text",
name="username"
) // 和上边效果一样

非转义属性

为了阻止跨站脚本,在默认情况下所有的属性都会被转义,但是如果你真的需要一些特殊字符,比如:<</code > 或 < code>></code > 等,可以使用 < code>!=</code > 替代 < code>=

1
2
div(escaped="<code>")
div(unescaped!="<code>")

布尔属性

Pug(Jade) 可以直接接受 true</code > 和 < code>false</code > 赋值给布尔属性,而且当你缺省赋值时,默认为 < code>true

1
2
3
input(type="checkbox",checked)
input(type="checkbox",checked="true")
input(type="checkbox",checked="false")

样式属性

在 style 属性中会有多个值,可以把 style 属性的值看做是一个 JavaScript 对象

1
p(style={color:red,font-size:17px})

字面量声明 class 属性和 id 属性

当使用字面量声明 class 和 id 属性时,Pug(Jade) 支持使用 CSS 的类选择器和 id 选择器的方式,这也是最简单的方法。

1
2
a.commit
a#commit

相当于 HTML 中的:
1
2
<a class="commit">
<a id="commit">

还可以声明分类。而且对于分类,Pug(Jade) 还有另一种声明方法,就是把分类拆分成数组,然后直接使用数组对 class 属性赋值。
1
2
3
4
a.commit.first

- var classes = ['commit','first'];
a(class=classes)

相当于 HTML 中的:
1
<a class="commit first"></a>

&Attributes

Pug(Jade) 提供 & attributes 是为了方便我们将整个对象传递给属性,主要用于为属性整体赋值和将属性穿个 Mixin

1
2
- var attributes = {'data-foo': 'bar'};
div#foo(data-bar="foo")&attributes(attributes)

相当于 HTML 中:
1
<div id="foo" data-bar="foo" data-foo="bar"></div>

转义字符插入

将转义字符写入变量,然后用 #{var}</code > 的方式插入,这种插入方式会将特殊字符串进行转义。

1
2
3
4
5
6
7
- var title = "On Dogs: Man's Best Friend";
- var author = "enlore";
- var theGreat = "<span>escape!</span>";

h1= title
p Written with love by #{author}
p This will be safe: #{theGreat}

而且在 #{} 中不仅可以插入变量,其实还可以插入 JavaScript 代码
1
2
- var msg = "hello world"
p message is #{msg.toUpperCase()}

非转义字符插入

非转义字符串插入和转义字符串插入用法一样,只是使用的是!{},而且在遇到特殊字符是不对其进行转义

1
2
3
4
5
6
7
- var title = "On Dogs: Man's Best Friend";
- var author = "enlore";
- var theGreat = "<span>escape!</span>";

h1= title
p Written with love by !{author}
p This will be safe: !{theGreat}

HTML 标签插入

标签插入使用的操作符是 #[],在操作符中使用 Pug(Jade) 标签声明代码即可。

1
p this is a link #[a(href="http://Pug(Jade).terrynie.com")]

相当于 HTML 中:
1
<p>this is a link <a href="http://Pug(Jade).terrynie.com"></a></p>

插入文本

有三种方式:管道符文本 |、标签行内文本、标签快文本。

管道符文本

管道符出现在每行第一个非空格字符时,该行就会被认为是文本。

1
2
3
p jade is better than pug
| Plain text can include <strong>html</strong>
p i think

转换成 HTML 为:
1
2
3
<p>jade is better than pug</p>
Plain text can include <strong>html</strong>
<p>i think</p>

标签行内文本

将文本放在标签之后,并用空格与标签隔开即可。

1
p this is a inline text in a tag

相当于 HTML 中:
1
<p>this is a inline text in a tag</p>

标签块文本

script</code > 或 < code>style</code > 标签的后面紧跟 < code>.</code > 即可(不能有空格)

1
2
3
4
5
script.
if (usingPug(Jade))
console.log('you are awesome')
else
console.log('use Pug(Jade)')

Block

在 Pug(Jade) 中,允许使用 block 结合 extends 关键字预定义一个模板供其他模板调用。调用时,如果父模板中定义了某块内容,而子模板中没有定义时,默认显示父模板中的内容。 Pug(Jade) 通过这种方法实现模板的继承和重用。
除了继承模板,还可以使用 append 和 prepend 对继承的模板进行扩展。

模板继承

block 的声明方式

1
2
block blockName
content

举例
layout.Pug(Jade) 中的 head 中定义一个 block ,名称为 scripts ,默认内容为 script(src='/jquery.js') ,在 body 中定义一个 block ,名称为 content ,默认内容为空。
page.Pug(Jade) 中用 extends 继承 layout.Pug(Jade) 模板,并且重新定义名为 scriptsblock
layout.Pug(Jade)
1
2
3
4
5
6
7
8
- var title = 'blog'
html
head
title My Site - #{title}
block scripts
script(src='/jquery.js')
body
block content

page.Pug(Jade)

1
2
3
4
extends ./layout.Pug(Jade)

block scripts
script(src='/bootstrap.js')

生成的 HTML 文件:

1
2
3
4
5
6
7
8
9
<html>
<head>
<title>My Site - blog</title>
<script src="/bootstrap.js"></script>
</head>
<body>
<h1>title</h1>
</body>
</html>

page.Pug(Jade) 中使用 extends 继承了 layout.Pug(Jade) ,并且默认覆盖了 layout.Pug(Jade) 中的 block scripts ,但是没有指定 block content 的内容,所以 block content 中还是 layout.Pug(Jade) 中的内容。

Block Append & Block Prepend

append 可以在父模板中的 block 内容后面追加内容
举例,继承 layout.Pug(Jade) 文件,然后在名为 scriptsblock 内容后面追加内容 script(src='/bootstrap.js')

1
2
3
extends ./layout.Pug(Jade)
block append scripts
script(src='/bootstrap.js')

转换成 HTML 文件为:
1
2
3
4
5
6
7
8
9
<html>
<head>
<title>My Site - blog</title>
<script src="/jquery.js"></script>
<script src="/bootstrap.js"></script>
</head>
<body>
</body>
</html>

prepend 可以在父模板中的 block 内容前面添加内容
举例,继承 layout.Pug(Jade) 文件,然后在名为 scriptsblock 内容前面追加内容 script(src='/bootstrap.js')

1
2
3
extends ./layout.Pug(Jade)
block prepend scripts
script(src='/bootstrap.js')

转换成 HTML 文件为:
1
2
3
4
5
6
7
8
9
<html>
<head>
<title>My Site - blog</title>
<script src="/bootstrap.js"></script>
<script src="/jquery.js"></script>
</head>
<body>
</body>
</html>

在使用 block appendblock prepend 时, block 是可选的,简写形式可将其省略。
省略之后的命令为:

1
2
3
4
5
append scripts
script(src='/bootstrap.js')

prepend scripts
script(src='/bootstrap.js')

Includes

引入 Pug(Jade) 文件

Includes 是代码复用的另一种方式,允许你将一个 Pug(Jade) 文件中的内容引入到另一个 Pug(Jade) 文件中。
举例,创建两个名为 head.Pug(Jade)footer.Pug(Jade) 的文件,并在 page.Pug(Jade) 文件中使用 includes 命令,来引入两个文件中的内容。
head.Pug(Jade)

1
2
head
title This is head

footer.Pug(Jade)
1
footer this is a footer

page.Pug(Jade)
1
2
3
4
5
html
include ./head.Pug(Jade)
body
h1 this is a include demo
include ./footer.Pug(Jade)

生成的 HTML 文件为:
1
2
3
4
5
6
7
8
9
<html>
<head>
<title>This is head</title>
</head>
<body>
<h1>this is a include demo</h1>
<footer>this is a footer</footer>
</body>
</html>

引入文本文件

除了可以使用 includes 引入 Pug(Jade) 文件,还可以使用它引入文本文件,比如 CSS 或 JavaScript 脚本文件。引入样式文件和脚本文件时,文件内容被作为纯文本引入到 Pug(Jade) 文件中。注意引入 CSS 和 JavaScript 这两类文件之前,要先分别加入声明 stylescript ,这样转换出来的 HTML 文件才能正确被浏览器编译。
举例,创建一个名为 style.css 的文件和一个名为 script.js 的文件,然后在 index.Pug(Jade) 中引入这两个文件,并且转换为 HTML 文件。
style.css

1
h1 {color: red;}

script.js
1
console.log('You are awesome');

index.Pug(Jade)
1
2
3
4
5
6
7
8
9
10
doctype html
html
head
style
include style.css
body
h1 My Site
p Welcome to my super lame site.
script
include script.js

转换成 HTML 为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!doctype html>
<html>
<head>
<style>
h1 {color: red;}
</style>
</head>
<body>
<h1>My Site</h1>
<p>Welcome to my super lame site.</p>
<script>
console.log('You are awesome');
</script>
</body>
</html>

过滤器

过滤器允许你在 Pug(Jade) 模板中使用其他语言,然后 Pug(Jade) 自动调用所需的解释器进行转换。所使用的符号就是 : 并在分号后加上使用的语言名称,目前支持的过滤器有以下几种:
| 语言名称 | 需要安装 |
|-|-|
|sass|sass.js|
|less|less.js|
|markdown|markdown-js 或 node-discount|
|cdata|/|
|coffeescript|coffee-script|
举例

1
2
3
4
5
6
7
:markdown
# Markdown

I often like including markdown documents.
script
:coffee-script
console.log 'This is coffee script'

转化成 HTML 为

1
2
3
<h1>Markdown</h1>
<p>I often like including markdown documents.</p>
<script>console.log('This is coffee script')</script>

循环

Pug(Jade) 支持两种主要的循环:each 和 while。另外还有一个 for ,用法和 each 相同。

each

通过 each 迭代器可以快速迭代数组和对象,并且可以获取数组的索引和对象的键:
each.Pug(Jade):
ul
each val,idx in [1, 2, 3, 4, 5]
li #{val} is at #{idx}
each.html:

  • 1 is at 0
  • 2 is at 1
  • 3 is at 2
  • 4 is at 3
  • 5 is at 4

上面的例子只是简单的迭代获取数组中的内容,下面的这个例子将同时获取数组的索引和对应的内容:
each2.Pug(Jade):
ul
each val, index in [‘zero’, ‘one’, ‘two’]
li= index + ‘:’ + val
each2.html:

  • 0: zero
  • 1: one
  • 2: two

在免费送一个同时获取对象中键和值得例子吧:
each3.Pug(Jade):
ul
each val, index in {1:’one’,2:’two’,3:’three’}
li= index + ‘:’ + val
each3.html:

  • 1: one
  • 2: two
  • 3: three

同样,上边的几个例子中的 each 完全可以可以使用 for 来替换,for 可以被作为 each 的别名来使用。

while

除了使用 each 之外还有就是可以使用 while 来循环,用法也很简单。
while.Pug(Jade):

  • var n = 0
    ul
    while n < 4
    li= n++
    while.html:
    • 0
    • 1
    • 2
    • 3

    这就是 while 的用法,和其他语言的使用方法几乎都是一样的。

Mixin

在Pug(Jade)中,除了前面讲的两种代码反复用方式:extends和includes之外,还有一个更加强大且常用的方式,那就是本节要讲的Mixin。Mixin更像一个函数,可以是无参的,也可以是有参的,定义之后只需要在希望使用它的地方调用即可,方便得很。