重要通知:本站内容已停止更新,请访问新域名dp2px.com

pug模板引擎(下)

逻辑语法

以下是关于模板逻辑的语法。

JavaScript代码

不输出的代码

用 - 开始一段不直接进行输出的代码。

1
2
- for (var x = 0; x < 3; x++)
li item
1
2
3
<li>item</li>
<li>item</li>
<li>item</li>

输出的代码

用=开始一段带有输出的代码,它应该是可以被求值的一个JavaScript表达式。为安全起见,它将被HTML转义。

1
2
3
p
= '这个代码被 <转义> 了!'
p= '这个代码被 <转义> 了!'

1
2
3
4
5

<p>这个代码被 &lt;转义&gt; 了!
</p>
<p>这个代码被 &lt;转义&gt; 了!</p>
​`

不转义的输出代码

用 != 开始一段不转义的,带有输出的代码。这将不会做任何转义,所以用于执行用户的输入将会不安全。

1
2
3
p
!= '这段文字 <strong>没有</strong> 被转义!'
p!= '这段文字' + ' <strong>没有</strong> 被转义!'

1
2
3
<p>这段文字 <strong>没有</strong> 被转义!
</p>
<p>这段文字 <strong>没有</strong> 被转义!</p>

变量

内容变量

使用=或#{}来进行变量的真实值替换。

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

h1= title
p #{author} 笔下源于真情的创作。
p 这是安全的:#{theGreat}
1
2
3
<h1>On Dogs: Man's Best Friend</h1>
<p>enlore 笔下源于真情的创作。</p>
<p>这是安全的:&lt;span&gt;转义!&lt;/span&gt;</p>

在 #{ 和 } 里面的代码也会被求值、转义,并最终嵌入到模板的渲染输出中。

1
2
- var msg = "not my inside voice";
p This is #{msg.toUpperCase()}

1
<p>This is NOT MY INSIDE VOICE</p>

Pug 足够聪明来分辨到底哪里才是嵌入表达式的结束,所以不用担心表达式中有 },也不需要额外的转义。

1
p 不要转义 #{'}'}!
1
2
<p>不要转义 }!</p>
​`

如果需要表示一个 #{ 文本,可以转义它,也可以用嵌入功能来生成。

1
2
p Escaping works with \#{interpolation}
p Interpolation works with #{'#{interpolation}'} too!

1
2
<p>Escaping works with #{interpolation}</p>
<p>Interpolation works with #{interpolation} too!</p>

使用!{}嵌入没有转义的文本进入模板中。

1
2
3
- var riskyBusiness = "<em>我希望通过外籍教师 Peter 找一位英语笔友。</em>";
.quote
p 张三:!{riskyBusiness}
1
2
3
<div class="quote">
<p>张三:<em>我希望通过外籍教师 Peter 找一位英语笔友。</em></p>
</div>

[注意]如果直接使用用户提供的数据,未进行转义的内容可能会带来安全风险。

属性变量

如果要在属性当中使用变量的话,需要进行如下操作。

1
2
3
4
5
- var url = 'pug-test.html';
a(href='/' + url) 链接
= '\n'
- url = 'https://example.com/'
a(href=url) 另一个链接
1
2
<a href="/pug-test.html">链接</a>
<a href="https://example.com/">另一个链接</a>

如果JavaScript运行时支持 ECMAScript 2015 模板字符串,还可以使用下列方式来简化属性值。

1
2
3
4
5
- var btnType = 'info'
- var btnSize = 'lg'
button(type='button' class='btn btn-' + btnType + ' btn-' + btnSize)
= '\n'
button(type='button' class=`btn btn-${btnType} btn-${btnSize}`)

1
2
3
<button class="btn btn-info btn-lg" type="button"></button>

<button class="btn btn-info btn-lg" type="button"></button>

&attributes 语法可以将一个对象转化为一个元素的属性列表。

1
2
3
4
div#foo(data-bar="foo")&attributes({'data-foo': 'bar'})
- var attributes = {};
- attributes.class = 'baz';
div#foo(data-bar="foo")&attributes(attributes)
1
2
<div id="foo" data-bar="foo" data-foo="bar"></div>
<div class="baz" id="foo" data-bar="foo"></div>

变量来源

变量来源有三种,分别是pug文件内部、命令行参数和外部JSON文件。

  1. pug文件内部
    1
    2
    - var val = "测试内容"
    p= val
1
<p>测试内容</p>
  1. 命令行参数

使用–obj参数,就可以跟随一个对象形式的参数

1
>>> $ pug index.pug -w -P --obj '{val:"命令行数据"}

  1. 外部JSON文件

使用-O,跟随一个JSON文件的路径即可

1
>>> $ pug index.pug -w -P -O test.json

这三种方式,pug文件内部的变量优先级最多,而外部JSON文件和命令行传参优先级相同。

条件

pug 的条件判断的一般形式的括号是可选的,所以可以省略掉开头的 -,效果完全相同。类似一个常规的 JavaScript 语法形式。

if…else…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- var user = { description: 'foo bar baz' }
- var authorised = false
#user
if user.description
h2.green 描述
p.description= user.description
else if authorised
h2.blue 描述
p.description.
用户没有添加描述。
不写点什么吗……
else
h2.red 描述
p.description 用户没有描述
1
2
3
4
<div id="user">
<h2 class="green">描述</h2>
<p class="description">foo bar baz</p>
</div>

pug 同样也提供了它的反义版本 unless.

1
2
3
4
5
- var user = { description: 'foo bar baz', name:'aaa' }
unless user.isAnonymous
p 您已经以 #{user.name} 的身份登录
if !user.isAnonymous
p 您已经以 #{user.name} 的身份登录
1
2
<p>您已经以 aaa 的身份登录</p>
<p>您已经以 aaa 的身份登录</p>

switch

case 是 JavaScript 的 switch 指令的缩写,并且它接受如下的形式.

1
2
3
4
5
6
7
8
- var friends = 10
case friends
when 0
p 您没有朋友
when 1
p 您有一个朋友
default
p 您有 #{friends} 个朋友
1
<p>您有 10 个朋友</p>

在某些情况下,如果不想输出任何东西的话,可以明确地加上一个原生的 break 语句。

1
2
3
4
5
6
7
8
- var friends = 0
case friends
when 0
- break
when 1
p 您的朋友很少
default
p 您有 #{friends} 个朋友

循环

pug 目前支持两种主要的迭代方式: each 和 while

each

这是 Pug 的首选迭代方式

1
2
3
ul
each val in [1, 2, 3, 4, 5]
li= val
1
2
3
4
5
6
7
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>

可以在迭代时获得索引值

1
2
3
ul
each val, index in ['〇', '一', '二']
li= index + ': ' + val
1
2
3
4
5
<ul>
<li>0: 〇</li>
<li>1: 一</li>
<li>2: 二</li>
</ul>

能够迭代对象中的键值

1
2
3
ul
each val, index in {1:'一',2:'二',3:'三'}
li= index + ': ' + val
1
2
3
4
5
<ul>
<li>1: 一</li>
<li>2: 二</li>
<li>3: 三</li>
</ul>

用于迭代的对象或数组仅仅是个 JavaScript 表达式,因此它可以是变量、函数调用的结果,又或者其他

1
2
3
4
- var values = [];
ul
each val in values.length ? values : ['没有内容']
li= val
1
2
3
<ul>
<li>没有内容</li>
</ul>

还能添加一个 else 块,这个语句块将会在数组与对象没有可供迭代的值时被执行

1
2
3
4
5
6
- var values = [];
ul
each val in values
li= val
else
li 没有内容
1
2
3
<ul>
<li>没有内容</li>
</ul>

[注意]也可以使用 for 作为 each 的别称

while

也可以使用 while 来创建一个循环

1
2
3
4
- var n = 0;
ul
while n < 4
li= n++
1
2
3
4
5
6
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>

混入

混入是一种允许在 Pug 中重复使用一整个代码块的方法

1
2
3
4
5
6
7
8
9
//- 定义
mixin list
ul
li foo
li bar
li baz
//- 使用
+list
+list
1
2
3
4
5
6
7
8
9
10
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
</ul>
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
</ul>

混入可以被编译成函数形式,并传递一些参数

1
2
3
4
5
6
mixin pet(name)
li.pet= name
ul
+pet('猫')
+pet('狗')
+pet('猪')
1
2
3
4
5
<ul>
<li class="pet"></li>
<li class="pet"></li>
<li class="pet"></li>
</ul>

混入也可以把一整个代码块像内容一样传递进来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mixin article(title)
.article
.article-wrapper
h1= title
if block
block
else
p 没有提供任何内容。

+article('Hello world')

+article('Hello world')
p 这是我
p 随便写的文章
1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="article">
<div class="article-wrapper">
<h1>Hello world</h1>
<p>没有提供任何内容。</p>
</div>
</div>
<div class="article">
<div class="article-wrapper">
<h1>Hello world</h1>
<p>这是我</p>
<p>随便写的文章</p>
</div>
</div>

混入也可以隐式地,从“标签属性”得到一个参数 attributes

1
2
3
4
mixin link(href, name)
a(class!=attributes.class href=href)= name

+link('/foo', 'foo')(class="btn")

1
<a class="btn" href="/foo">foo</a>

也可以直接用 &attributes 方法来传递 attributes 参数

1
2
3
4
mixin link(href, name)
a(href=href)&attributes(attributes)= name

+link('/foo', 'foo')(class="btn")
1
<a class="btn" href="/foo">foo</a>

可以用剩余参数(rest arguments)语法来表示参数列表最后传入若干个长度不定的参数

1
2
3
4
5
6
mixin list(id, ...items)
ul(id=id)
each item in items
li= item

+list('my-list', 1, 2, 3, 4)
1
2
3
4
5
6
<ul id="my-list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>

文件包含

包含(include)功能允许把另外的文件内容插入进来

1
2
3
4
5
6
7
8
//- index.pug
doctype html
html
include includes/head.pug
body
h1 我的网站
p 欢迎来到我这简陋得不能再简陋的网站。
include includes/foot.pug

被包含的如果不是 pug 文件,那么就只会当作文本内容来引入

文件继承

pug 支持使用 block 和 extends 关键字进行模板的继承。一个称之为“块”(block)的代码块,可以被子模板覆盖、替换。这个过程是递归的。pug 的块可以提供一份默认内容,当然这是可选的。

1
2
3
4
5
6
7
8
9
10
11
12
//- layout.pug
html
head
   meta(charset="UTF-8")
title 我的站点 - #{title}
block scripts
script(src='/jquery.js')
body
block content
block foot
#footer
p 一些页脚的内容

现在来扩展这个布局:只需要简单地创建一个新文件,并如下所示用一句 extends 来指出这个被继承的模板的路径。现在可以定义若干个新的块来覆盖父模板里对应的“父块”。值得注意的是,因为这里的 foot 块 没有 被重定义,所以会依然输出“一些页脚的内容”

1
2
//- pet.pug
p= petName
1
2
3
4
5
6
7
8
9
10
11
12
13
//- page.pug
- var title = '宠物'
doctype html
html
head
meta(charset='UTF-8')
title 我的站点 - #{title}
block scripts
script(src='/jquery.js')
body
block content
block foot
p 一些页脚的内容
1
2
3
4
5
6
7
8
9
10
11
12
//- page-a.pug
extends layout.pug

block scripts
script(src='/jquery.js')
script(src='/pets.js')

block content
h1= title
- var pets = ['猫', '狗']
each petName in pets
include pet.pug
1
>>> $ pug pug-test -w -P    //pug-test是存放文件夹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- pug-a.html 文件-->

<!DOCTYPE html >
<html>
<head>
<meta charset="UTF-8"/>
<title>我的站点 - 宠物</title>
<script src="/jquery.js"></script>
<script src="/pets.js"></script>
</head>
<body>
<h1>宠物</h1>
<p></p>
<p></p>
<p>一些页脚的内容</p>
</body>
</html>

同样,也可以覆盖一个块并在其中提供一些新的块。如下所示,content 块现在暴露出两个新的块 sidebar 和 primary 用来被扩展。当然,它的子模板也可以把整个 content 给覆盖掉。

1
2
3
4
5
6
7
8
9
10
//- sub-layout.pug
extends page.pug

block content
.sidebar
block sidebar
p 什么都没有
.primary
block primary
p 什么都没有
1
2
3
4
5
6
7
8
9
10
//- page-b.pug
extends sub-layout.pug

block content
.sidebar
block sidebar
p 什么都没有
.primary
block primary
p 什么都没有
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- page-b.html 文件 -->

<!DOCTYPE html >
<html>
<head>
<meta charset="UTF-8"/>
<title>我的站点 - 宠物</title>
<script src="/jquery.js"></script>
</head>
<body>
<div class="sidebar">
<p>什么都没有</p>
</div>
<div class="primary">
<p>什么都没有</p>
</div>
<p>一些页脚的内容</p>
</body>
</html>

扩展

pug 允许去替换(默认的行为)、prepend(向头部添加内容),或者 append(向尾部添加内容)一个块。 假设有一份默认的脚本要放在 head 块中,而且希望将它应用到 每一个页面,可以进行如下操作。

1
2
3
4
5
6
7
8
//- layout.pug
html
head
block head
script(src='/vendor/jquery.js')
script(src='/vendor/caustic.js')
body
block content

现在假设有一个页面,那是一个 JavaScript 编写的游戏。希望把一些游戏相关的脚本也像默认的那些脚本一样放进去,那么只要简单地 append 这个块:

1
2
3
4
5
6
7
8
//- page.pug
extends layout.pug

block prepend head
script(src='/vendor/three.js')

block append head
script(src='/game.js')

当使用 block append 或者 block prepend 时,block 关键字是可省略的:

1
2
3
4
5
6
7
8
//- page.pug
extends layout.pug

prepend head
script(src='/vendor/three.js')

append head
script(src='/game.js')

简易模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//- index.pug
doctype html
html
head
meta(charset="UTF-8")
title= documentTitle
each val in srcStyles
link(href= baseStyle +'/' + val)
body
header.hd
nav.hd-navbar.m-navbar.m-navbar_primary
.hd-navbar-tel 联系方式: #{tel}
ul.hd-navbar-nav
each val in mainNavItem
li.Hnn-item.m-btn.m-btn_info
a(href="#")= val

section.main
h1.main-title 我的文档
p.main-content.
这是一个很长很长而且还很无聊的段落,还没有结束,是的,非常非常地长。
突然出现了一个 #[strong 充满力量感的单词],这确实让人难以 #[em 忽视]。

footer.ft
p Copyright (c) 小火柴的蓝色理想

each val in srcScripts
script(src=baseScript + '/' + val)
1
2
3
4
5
6
7
8
9
10
//- data.json
{
"documentTitle":"测试文档",
"tel":"400-888-8888",
"mainNavItem":['登录','注册','关于','帮助'],
"baseStyle":'style',
"srcStyles":['bootstrap.css','main.css'],
"baseScript":'/js',
"srcScripts":['jquery.js','app.js']
}
您的支持是我创作源源不断的动力
------------ 本文结束#代码永无止境 ------------

此文由 水寒原创 采用 保留署名-非商业性使用-禁止演绎 4.0-国际许可协议
本文首发于[吉格斯实验室] 博客( http://www.dp2px.com ),版权所有,转载请声明作者和原文链接。

0%