前面的话

  为什么要引入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)的更多相关文章

  1. 学习篇:NodeJS中的模板引擎:jade

    NodeJS 模板引擎作用:生成页面 在node常用的模板引擎一般是 1.jade --破坏式的.侵入式.强依赖(对原有的html体系不友好,走自己的一套体系)2.ejs --温和的.非侵入式的.弱依 ...

  2. [js高手之路]Node.js模板引擎教程-jade速学与实战1

    环境准备: 全局安装jade: npm install jade -g 初始化项目package.json: npm init --yes 安装完成之后,可以使用 jade --help 查看jade ...

  3. 模板引擎之-jade

    ##### 首先我们安装jade模板引擎并编译`npm install jade --global`在项目文件夹下创建一个`index.jade`文件,并且写入```doctypehtml head ...

  4. 模板引擎之jade 学习

    jade 模板引擎在node express 开发中有较多的使用,首先我们看一个简单的使用jade 生成的html 页面的标签代码: doctype html html(lang="en&q ...

  5. [js高手之路]Node.js模板引擎教程-jade速学与实战1-基本用法

    环境准备: 全局安装jade: npm install jade -g 初始化项目package.json: npm init --yes 安装完成之后,可以使用 jade --help 查看jade ...

  6. [js高手之路]Node.js模板引擎教程-jade速学与实战4-模板引用,继承,插件使用

    一.block 模块复用 把需要复用的模块用block定义 block后面跟上模块的名字,引用一次block 内容就会被复用一次 编译之后的结果: 二,继承模板(extends) 在实际开发中,网站的 ...

  7. [js高手之路]Node.js模板引擎教程-jade速学与实战2-流程控制,转义与非转义

    一.转义与非转义 jade模板文件代码: doctype html html head meta(charset='utf-8') title jade学习-by ghostwu body h3 转义 ...

  8. [js高手之路]Node.js模板引擎教程-jade速学与实战3-mixin

    强大的mixin mixin类似于函数的功能,可以达到模块复用的效果 mixin show: 定义一个类似函数的功能,名字叫show,里面的就是他的内容 +show: 调用show,每调用一次执行一次 ...

  9. Express全系列教程之(十):jade模板引擎

    一.前言 随着前端业务的不断发展,页面交互逻辑的不断提高,让数据和界面实现分离渐渐被提了出来.JavaScript的MVC思想也流行了起来,在这种背景下,基于node.js的模板引擎也随之出现. 什么 ...

随机推荐

  1. 设计模式二:MVC

    先附上部分代码: /* *MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式.这种模式用于应用程序的分层开发. *Model(模型) - 模型代表一个存取数据的对 ...

  2. SQL数据库的多表查询

    多表查询分为 内.外连接 外连接分为左连接(left join 或left outer join).右连接(right join 或者 right outer join).和完整外部连接 (full ...

  3. css清除浮动的八大方法

    清除浮动是每一个 web前台设计师必须掌握的机能.css清除浮动大全,共8种方法. 浮动会使当前标签产生向上浮的效果,同时会影响到前后标签.父级标签的位置及 width height 属性.而且同样的 ...

  4. 关于oracle数据库备份还原-impdp,expdp

    初始化: -- 创建表空间 CREATE TABLESPACE 表空间名 DATAFILE '文件名.dat' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE UNL ...

  5. [原创] 利用前端+php批量生成html文件,传入新文本,输出新的html文件

    本人因为要想自己写个小说网站练练手,在其中遇到的一些问题,将其解决方法总结出来,例如: 1:小说网站存储了大量的小说,每个小说主页都很相似,url不同,不是使用的history属性改写的,所以如果人工 ...

  6. C#基础知识-面向对象思想之继承(八)

    上一篇的标题编程思想我觉得不是很符合主题,因为编程思想的范围太大了,不仅仅是封装 继承 多态,所以比较符合主题的应该是面向对象思想.这一篇中将继续叙述面向对象思想中的继承. 从字面来看继承表达的意思已 ...

  7. CSS3学习系列之选择器(四)

    使用选择器来插入文字 css2中,使用before选择器在元素前面插入内容,使用after选择器在元素后面插入内容,在选择器的content属性中定义要插入的内容.将content属性值设定为none ...

  8. Redis数据类型之Set

          前言:set类似于数学上面的集合概念,包含的元素无序,不能重复,能进行交.并.差操作. 一.内部原理              set数据结构,也是随着元素数目的多少而变化.当set中添加 ...

  9. B. Karen and Coffee

    B. Karen and Coffee time limit per test 2.5 seconds memory limit per test 512 megabytes input standa ...

  10. Redis中的基本数据结构

    Redis基础数据结构 基础数据结构 sds简单动态字符串 数据结构 typedef struct sdstr{ int len // 字符串分配的字节 int free // 未使用的字节数 cha ...