pug模板引擎(原jade)
前面的话
为什么要引入pug,pug有什么特别之处呢?有一些嵌套层次较深的页面,可能会出现巢状嵌套,如下图所示

在后期维护和修改时,一不小心少了一个尖括号,或者某个标签的开始和闭合没有对应上,就会导致DOM结构的混乱甚至是错误。所以,有人发明了HAML,它最大的特色就是使用缩进排列来代替成对标签。受HAML的启发,pug进行了javascript的实现。
Pug原名不叫Pug,是大名鼎鼎的jade,后来由于商标的原因,改为Pug,哈巴狗。其实只是换个名字,语法都与jade一样。丑话说在前面,Pug有它本身的缺点——可移植性差,调试困难,性能并不出色,但使用它可以加快开发效率。本文将详细介绍pug模板引擎
安装
使用npm安装pug
- $ npm install pug
但运行pug命令时,提示pug命令未找到

这时,需要安装pug命令行工具pug-cli
[注意]一定要全局安装pug-cli,否则无法正常编译
- npm install pug-cli -g
再运行pug命令时,正常执行

命令行
在学习pug基础语法之前,首先要了解pug的命令行的使用
【基础编译】
将如下内容输入文件中,并命名为index.pug
- html
- head
- title aaa
- body
在命令行中敲入pug index.pug即可实现基础编译

在当前目录下生成一个index.html,是index.pug编译后的结果

【sublime两列设置】
但是,这样查看并不方便。下面将sublime设置为两列放置,将index.pug和index.html分别放置在左右两列,方便查看

【自动编译】
使用pug -w功能可以实现自动编译

更改index.pug文件并保存后,index.html文件会实时更新为最新的编译的文件

【标准版HTML】
如上所示,默认地,pug编译出的HTML文件是压缩版的。如果要编译标准版的HTML文件,需要设置-P参数
- pug index.html -P
【路径设置】
如果并不希望在当前目录下输入编译后的HTML文件,而是有自定义目录的需求,则需要设置-o参数
如下设置,index.html将输入到a目录下面,如果a目录不存在,则会新建a目录
- pug index.pug -o a
【重命名】
默认地,编译后的HTML与pug文件同名。如果需要重命名,则可以进行如下设置
通过如下设置,可以同时设置路径和名称
[注意]这里的路径必须提前建立好,否则不会成功
- pug <xx.pug> <xx/xx.html>
最终,test.html文件被保存到templates目录下

【批量编译】
假设,编译href目录下所有的pug文件

结构语法
下面介绍关于结构的基础语法
标签
【树状】
在默认情况下,在每行文本的开头(或者紧跟白字符的部分)书写这个 HTML 标签的名称。使用缩进来表示标签间的嵌套关系,这样可以构建一个 HTML 代码的树状结构
- ul
- li Item A
- li Item B
- li Item C

【内联】
为了节省空间, Pug 嵌套标签提供了一种内联式语法
- a: img

【自闭合】
Pug知道哪些元素是自闭合的,也可以通过在标签后加上 /
来明确声明此标签是自闭合的
- img
- input
- img/
- input/

【DOCTYPE】
HTML5的DOCTYPE书写如下
- doctype html

也可以自定义一个 doctype 字面值
- doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"

内容
Pug 提供了三种常用的方式来放置内容
【管道文本】
这是最简单的向模板添加纯文本的方法。只需要在每行前面加一个 |
字符,这个字符在类 Unix 系统下常用作“管道”功能,因此得名
- | 纯文本当然也可以包括 <strong>HTML</strong> 内容。
- p
- | 但它必须单独起一行。

【标签内文本】
这实际上是最常见的情况,文本只需要和标签名隔开一个空格即可
- p 纯文本当然也可以包括 <strong>HTML</strong> 内容。

【嵌入大段文本】
有时可能想要写一个大段文本块。比如嵌入脚本或者样式。只需在标签后面接一个 .
即可
[注意]不要有空格
- script.
- if (usingPug)
- console.log('这是明智的选择。')
- else
- console.log('请用 Pug。')

属性
标签属性和 HTML 语法非常相似,它们的值就是普通的 JavaScript 表达式。可以用逗号作为属性分隔符,也可以不加逗号
- a(href='baidu.com') 百度
- = '\n'
- a(class='button' href='baidu.com') 百度
- = '\n'
- a(class='button', href='baidu.com') 百度

【多行属性】
如果有很多属性,可以把它们分几行写
- input(
- type='checkbox'
- name='agreement'
- checked
- )

【长属性】
如果有一个很长的属性,并且JavaScript运行时引擎支持ES2015模板字符串,可以使用它来写属性值
- input(data-json=`
- {
- "非常": "长的",
- "数据": true
- }
- `)

【特殊字符】
如果属性名称中含有某些奇怪的字符,可能会与 JavaScript 语法产生冲突的话,可以将它们使用 ""
或者 ''
括起来。还可以使用逗号来分割不同的属性
- div(class='div-class', (click)='play()')
- div(class='div-class' '(click)'='play()')

【转义属性】
默认情况下,所有的属性都经过转义(即把特殊字符转换成转义序列)来防止诸如跨站脚本攻击之类的攻击方式。如果要使用特殊符号,需要使用 !=
而不是 =
[注意]未经转义的缓存代码十分危险。必须正确处理和过滤用户的输入来避免跨站脚本攻击
- div(escaped="<code>")
- div(unescaped!="<code>")

【布尔值】
在Pug中,布尔值属性是经过映射的,这样布尔值(true
和false)
就能接受了。没有指定值时,默认是true
- input(type='checkbox' checked)
- = '\n'
- input(type='checkbox' checked=true)
- = '\n'
- input(type='checkbox' checked=false)
- = '\n'
- input(type='checkbox' checked=true.toString())

【行内样式】
style
(样式)属性可以是一个字符串(就像其他普通的属性一样)还可以是一个对象
- a(style={color: 'red', background: 'green'})

【类和ID】
类可以使用 .classname
语法来定义,ID 可以使用 #idname
语法来定义
考虑到使用 div
作为标签名这种行为实在是太常见了,所以如果省略掉标签名称的话,它就是默认值
- a.button
- .content
- ="\n"
- a#main-link
- #content

标签嵌入
标签支持一种标签嵌入的写法,形式如下
- #[标签名(标签属性) 标签内容]
对于内联标签来说,这种写法比较简单
- p.
- 这是一个很长很长而且还很无聊的段落,还没有结束,是的,非常非常地长。
- 突然出现了一个 #[strong 充满力量感的单词],这确实让人难以 #[em 忽视]。

【空格调整】
Pug 默认会去除一个标签前后的所有空格,而标签嵌入功能可以在需要嵌入的位置上处理前后空格
- p
- | 如果我不用嵌入功能来书写,一些标签比如
- strong strong
- | 和
- em em
- | 可能会产生意外的结果。
- p.
- 如果用了嵌入,在 #[strong strong] 和 #[em em] 旁的空格就会让我舒服多了。

注释
【单行注释】
单行注释和 JavaScript 类似,但是必须独立一行
- // 一些内容
- p foo
- p bar

【不输出注释】
只需要加上一个横杠,就可以使用不输出注释
- //- 这行不会出现在结果里
- p foo
- p bar

【块注释】
- body
- //
- 随便写多少字
- 都没关系。

【条件注释】
Pug 没有特殊的语法来表示条件注释(conditional comments)。不过因为所有以 <
开头的行都会被当作纯文本,因此直接写一个 HTML 风格的条件注释也是没问题的
- <!--[if IE ]>
- <html lang="en" class="lt-ie9">
- <![endif]-->
- <!--[if gt IE ]><!-->
- <html lang="en">
- <!--<![endif]-->

逻辑语法
以下是关于模板逻辑的语法
JS代码
【不输出的代码】
用 -
开始一段不直接进行输出的代码
- - for (var x = ; x < ; x++)
- li item

【输出的代码】
用=
开始一段带有输出的代码,它应该是可以被求值的一个JavaScript表达式。为安全起见,它将被HTML转义
- p
- = '这个代码被 <转义> 了!'
- p= '这个代码被 <转义> 了!'

【不转义的输出代码】
用 !=
开始一段不转义的,带有输出的代码。这将不会做任何转义,所以用于执行用户的输入将会不安全
- p
- != '这段文字 <strong>没有</strong> 被转义!'
- p!= '这段文字' + ' <strong>没有</strong> 被转义!'

变量
【内容变量】
使用=或#{}来进行变量的真实值替换
- - var title = "On Dogs: Man's Best Friend";
- - var author = "enlore";
- - var theGreat = "<span>转义!</span>";
- h1= title
- p #{author} 笔下源于真情的创作。
- p 这是安全的:#{theGreat}

在 #{
和 }
里面的代码也会被求值、转义,并最终嵌入到模板的渲染输出中
- - var msg = "not my inside voice";
- p This is #{msg.toUpperCase()}

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

如果需要表示一个 #{
文本,可以转义它,也可以用嵌入功能来生成
- p Escaping works with \#{interpolation}
- p Interpolation works with #{'#{interpolation}'} too!

使用!{}嵌入没有转义的文本进入模板中
- - var riskyBusiness = "<em>我希望通过外籍教师 Peter 找一位英语笔友。</em>";
- .quote
- p 李华:!{riskyBusiness}

[注意]如果直接使用用户提供的数据,未进行转义的内容可能会带来安全风险
【属性变量】
如果要在属性当中使用变量的话,需要进行如下操作
- - var url = 'pug-test.html';
- a(href='/' + url) 链接
- = '\n'
- - url = 'https://example.com/'
- a(href=url) 另一个链接

如果JavaScript运行时支持 ECMAScript 2015 模板字符串,还可以使用下列方式来简化属性值
- - 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}`)

&attributes
语法可以将一个对象转化为一个元素的属性列表
- div#foo(data-bar="foo")&attributes({'data-foo': 'bar'})
- - var attributes = {};
- - attributes.class = 'baz';
- div#foo(data-bar="foo")&attributes(attributes)

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

2、命令行参数
使用--obj参数,就可以跟随一个对象形式的参数


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


这三种方式,pug文件内部的变量优先级最多,而外部JSON文件和命令行传参优先级相同
如下所示,外部JSON文件和命令行传参两种方式都存在,由于--obj写在-w后面,最终以命令行传参为准

条件
Pug 的条件判断的一般形式的括号是可选的,所以可以省略掉开头的 -
,效果完全相同。类似一个常规的 JavaScript 语法形式
【if else】
- - 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 用户没有描述

Pug 同样也提供了它的反义版本 unless
- unless user.isAnonymous
- p 您已经以 #{user.name} 的身份登录。

【switch】
case
是 JavaScript 的 switch
指令的缩写,并且它接受如下的形式
- - var friends =
- case friends
- when
- p 您没有朋友
- when
- p 您有一个朋友
- default
- p 您有 #{friends} 个朋友

在某些情况下,如果不想输出任何东西的话,可以明确地加上一个原生的 break
语句
- - var friends =
- case friends
- when
- - break
- when
- p 您的朋友很少
- default
- p 您有 #{friends} 个朋友

也可以使用块展开的语法
- - var friends =
- case friends
- when : p 您没有朋友
- when : p 您有一个朋友
- default: p 您有 #{friends} 个朋友

循环
Pug 目前支持两种主要的迭代方式: each
和 while
【each】
这是 Pug 的首选迭代方式
- ul
- each val in [, , , , ]
- li= val

可以在迭代时获得索引值
- ul
- each val, index in ['〇', '一', '二']
- li= index + ': ' + val

能够迭代对象中的键值
- ul
- each val, index in {:'一',:'二',:'三'}
- li= index + ': ' + val

用于迭代的对象或数组仅仅是个 JavaScript 表达式,因此它可以是变量、函数调用的结果,又或者其他
- - var values = [];
- ul
- each val in values.length ? values : ['没有内容']
- li= val

还能添加一个 else
块,这个语句块将会在数组与对象没有可供迭代的值时被执行
- - var values = [];
- ul
- each val in values
- li= val
- else
- li 没有内容

[注意]也可以使用 for
作为 each
的别称
【while】
也可以使用 while
来创建一个循环
- - var n = ;
- ul
- while n <
- li= n++

混入
混入是一种允许在 Pug 中重复使用一整个代码块的方法
- //- 定义
- mixin list
- ul
- li foo
- li bar
- li baz
- //- 使用
- +list
- +list

混入可以被编译成函数形式,并传递一些参数
- mixin pet(name)
- li.pet= name
- ul
- +pet('猫')
- +pet('狗')
- +pet('猪')

混入也可以把一整个代码块像内容一样传递进来
- mixin article(title)
- .article
- .article-wrapper
- h1= title
- if block
- block
- else
- p 没有提供任何内容。
- +article('Hello world')
- +article('Hello world')
- p 这是我
- p 随便写的文章

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

也可以直接用 &attributes
方法来传递 attributes
参数
- mixin link(href, name)
- a(class!=attributes.class href=href)= name
- +link('/foo', 'foo')(class="btn")

[注意]+link(class="btn")
等价于 +link()(class="btn")
,因为 Pug 会判断括号内的内容是属性还是参数。但最好使用后面的写法,明确地传递空的参数,确保第一对括号内始终都是参数列表
可以用剩余参数(rest arguments)语法来表示参数列表最后传入若干个长度不定的参数
- mixin list(id, ...items)
- ul(id=id)
- each item in items
- li= item
- +list('my-list', , , , )

文件包含
包含(include)功能允许把另外的文件内容插入进来
- //- index.pug
- doctype html
- html
- include includes/head.pug
- body
- h1 我的网站
- p 欢迎来到我这简陋得不能再简陋的网站。
- include includes/foot.pug
- //- includes/head.pug
- head
- title 我的网站
- script(src='/javascripts/jquery.js')
- script(src='/javascripts/app.js')
- //- includes/foot.pug
- footer#footer
- p Copyright (c) foobar

被包含的如果不是 Pug 文件,那么就只会当作文本内容来引入
- //- index.pug
- doctype html
- html
- head
- style
- include style.css
- body
- h1 我的网站
- p 欢迎来到我这简陋得不能再简陋的网站。
- script
- include script.js
- /* style.css */
- h1 {
- color: red;
- }
- // script.js
- console.log('真了不起!');

文件继承
【覆盖】
Pug 支持使用 block
和 extends
关键字进行模板的继承。一个称之为“块”(block)的代码块,可以被子模板覆盖、替换。这个过程是递归的。
Pug 的块可以提供一份默认内容,当然这是可选的
- //- 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
块 没有 被重定义,所以会依然输出“一些页脚的内容”
- //- pet.pug
- p= petName
- //- 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

同样,也可以覆盖一个块并在其中提供一些新的块。如下所示,content
块现在暴露出两个新的块 sidebar
和 primary
用来被扩展。当然,它的子模板也可以把整个 content
给覆盖掉
- //- sub-layout.pug
- extends layout.pug
- block content
- .sidebar
- block sidebar
- p 什么都没有
- .primary
- block primary
- p 什么都没有
- //- page-b.pug
- extends sub-layout.pug
- block content
- .sidebar
- block sidebar
- p 什么都没有
- .primary
- block primary
- p 什么都没有

【扩展】
Pug 允许去替换(默认的行为)、prepend
(向头部添加内容),或者 append
(向尾部添加内容)一个块。 假设有一份默认的脚本要放在 head
块中,而且希望将它应用到 每一个页面,可以进行如下操作
- //- layout.pug
- html
- head
- block head
- script(src='/vendor/jquery.js')
- script(src='/vendor/caustic.js')
- body
- block content
现在假设有一个页面,那是一个 JavaScript 编写的游戏。希望把一些游戏相关的脚本也像默认的那些脚本一样放进去,那么只要简单地 append
这个块:
- //- 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
关键字是可省略的:
- //- page.pug
- extends layout.pug
- prepend head
- script(src='/vendor/three.js')
- append head
- script(src='/game.js')

简易模板
- //- 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)
- //- data.json
- {
- "documentTitle":"测试文档",
- "tel":"400-888-8888",
- "mainNavItem":['登录','注册','关于','帮助'],
- "baseStyle":'style',
- "srcStyles":['bootstrap.css','main.css'],
- "baseScript":'/js',
- "srcScripts":['jquery.js','app.js']
- }


pug模板引擎(原jade)的更多相关文章
- 学习篇:NodeJS中的模板引擎:jade
NodeJS 模板引擎作用:生成页面 在node常用的模板引擎一般是 1.jade --破坏式的.侵入式.强依赖(对原有的html体系不友好,走自己的一套体系)2.ejs --温和的.非侵入式的.弱依 ...
- [js高手之路]Node.js模板引擎教程-jade速学与实战1
环境准备: 全局安装jade: npm install jade -g 初始化项目package.json: npm init --yes 安装完成之后,可以使用 jade --help 查看jade ...
- 模板引擎之-jade
##### 首先我们安装jade模板引擎并编译`npm install jade --global`在项目文件夹下创建一个`index.jade`文件,并且写入```doctypehtml head ...
- 模板引擎之jade 学习
jade 模板引擎在node express 开发中有较多的使用,首先我们看一个简单的使用jade 生成的html 页面的标签代码: doctype html html(lang="en&q ...
- [js高手之路]Node.js模板引擎教程-jade速学与实战1-基本用法
环境准备: 全局安装jade: npm install jade -g 初始化项目package.json: npm init --yes 安装完成之后,可以使用 jade --help 查看jade ...
- [js高手之路]Node.js模板引擎教程-jade速学与实战4-模板引用,继承,插件使用
一.block 模块复用 把需要复用的模块用block定义 block后面跟上模块的名字,引用一次block 内容就会被复用一次 编译之后的结果: 二,继承模板(extends) 在实际开发中,网站的 ...
- [js高手之路]Node.js模板引擎教程-jade速学与实战2-流程控制,转义与非转义
一.转义与非转义 jade模板文件代码: doctype html html head meta(charset='utf-8') title jade学习-by ghostwu body h3 转义 ...
- [js高手之路]Node.js模板引擎教程-jade速学与实战3-mixin
强大的mixin mixin类似于函数的功能,可以达到模块复用的效果 mixin show: 定义一个类似函数的功能,名字叫show,里面的就是他的内容 +show: 调用show,每调用一次执行一次 ...
- Express全系列教程之(十):jade模板引擎
一.前言 随着前端业务的不断发展,页面交互逻辑的不断提高,让数据和界面实现分离渐渐被提了出来.JavaScript的MVC思想也流行了起来,在这种背景下,基于node.js的模板引擎也随之出现. 什么 ...
随机推荐
- opencv 删除二值化图像中面积较小的连通域
对于上图的二值化图像,要去除左下角和右上角的噪点,方法:使用opencv去掉黑色面积较小的连通域. 代码 CvSeq* contour = NULL; double minarea = 100.0; ...
- Docker-compose实战——Django+PostgreSQL
今天我们来用docker-compose 快速安装一个Django+PostgreSQL的开发环境. Compose简介 Compose 定位是“defining and running comple ...
- 每天一个JS 小demo之个人信息添加。主要知识点:DOM操作中的表格操作,节点操作
以下是简易效果: <!DOCTYPE html><html lang="en"><head> <meta charset="UT ...
- gradle 使用总结
什么是gradle 书面化解释: Gradle可以自动化地进行软件构建.测试.发布.部署.软件打包,同时也可以完成项目相关功能如:生成静态网站.生成文档等. Gradle是一种依赖管理工具. 它和ma ...
- Nmap脚本文件分析(AMQP协议为例)
Nmap脚本文件分析(AMQP协议为例) 一.介绍 上两篇文章 Nmap脚本引擎原理 编写自己的Nmap(NSE)脚本,分析了Nmap脚本引擎的执行过程,以及脚本文件的编写,这篇文章将以解析AMQ ...
- AVAudioFoundation(2):音视频播放
本文转自:AVAudioFoundation(2):音视频播放 | www.samirchen.com 本文主要内容来自 AVFoundation Programming Guide. 要播放 AVA ...
- angular.js小知识总结
angular-watch.html 代码如下: <script> var app = angular.module('app',[]); app.controller('ctrl',fu ...
- sqlserver 复制表结构(可以含有数据 或 只要表结构)
sqlserver 复制表结构(可以含有数据 或 只要表结构) SELECT * INTO bb FROM aa(NOLOCK) WHERE 1=0
- 《JavaScript高级程序设计》笔记一
第一章 JavaScript简介 一.JavaScript的起源 JavaScript诞生于1995年.当时,它的主要作用是处理一些输入验证操作.之前的话,都是把表单数据发送到服务器端,然后再去判断有 ...
- 在CentOS7上使用systemctl配置tomcat
最近买了一台阿里云,现在阿里云CentOS都已经支持7了(前面都是使用CentOS6),索性直接使用CentOS7,7上面目前最大区别就是service变成了现在的systemctl,简单的查了一下并 ...