完全掌握Pug模版引擎看这篇就够了

开始学习Pug之旅吧!

pug模块在npm中也是可用的。

$ npm install pug

概览

使用Pug模版引擎处理模板是很容易的,pug.compuile() 方法会将Pug源代码放入JavaScript函数中解析,该方法接受一个对象类型的参数(名为“locals”),该方法会对你的模版进行处理,并将处理后的HTML 字符串返回。

该解析函数是可以被复用的,设置不同的“locals”数据,会输出不同的HTML字符串。

//- template.pug
p #{name}'s Pug source code!
const pug = require('pug');

// Compile the source code
const compiledFunction = pug.compileFile('template.pug');

// Render a set of data
console.log(compiledFunction({
  name: 'Timothy'
}));
// "<p>Timothy's Pug source code!</p>"

// Render another set of data
console.log(compiledFunction({
  name: 'Forbes'
}));
// "<p>Forbes's Pug source code!</p>"

Pug还提供了 pug.render() 函数,该函数将编译和渲染两个步骤一次性完成,然而,模版函数将会在每次 render 函数被调用时重新编译,所以这对性能和效率的提升没有帮助,不过你可以使用 rendercache 参数,如此一来编译函数将会自动的存至缓存中,大大提升了编译的效率。

const pug = require('pug');

// Compile template.pug, and render a set of data
console.log(pug.renderFile('template.pug', {
  name: 'Timothy'
}));
// "<p>Timothy's Pug source code!</p>"

语法参考

属性

标签属性和HTML很相似(参数与参数间的逗号是可选的)。不过这里的参数值其实是JavaScript表达式。

(NOTE: 本页面使用的竖线符号(|)是为了空白控制。)

a(href='google.com') Google
|
|
a(class='button' href='google.com') Google
|
|
a(class='button', href='google.com') Google
<a href="google.com">Google</a>
<a class="button" href="google.com">Google</a>
<a class="button" href="google.com">Google</a>

一般的JavaScript表达式在这里也可以正确执行:

- var authenticated = true
body(class=authenticated ? 'authed' : 'anon')
<body class="authed"></body>

多行属性

如果你有多个属性,你可以通过多行书写他们:

input(
  type='checkbox'
  name='agreement'
  checked
)
<input type="checkbox" name="agreement" checked="checked" />

如果你的JavaScript运行时支持ES2015的 template strings (适用于 Node.js/io.js 1.0.0 及以后的版本),你可以使用如下的语法书写属性。这对于很长的属性值来说是很有用的:

input(data-json=`
  {
    "very-long": "piece of ",
    "data": true
  }
`)
<input data-json="
  {
    &quot;very-long&quot;: &quot;piece of &quot;,
    &quot;data&quot;: true
  }
" />

引号属性

如果你的属性名中包含非法的符号(比如 [] 或者 () 符号),可能会干扰JavaScript语法的解析,解决办法是使用双引号("")或者单引号(’’),或者逗号来分割不懂的属性:

//- 这个示例中,'(click)'将会被看作是调用了某个函数而非属性名
//- 从而引起一场错误
div(class='div-class' (click)='play()')
index.pug:4:11
      2| //- function call instead of a attribute name,
      3| //- resulting in the unusual error.
  > 4| div(class='div-class' (click)='play()')
-----------------^

Syntax Error: Assigning to rvalue

使用逗号分割,或者将属性名用引号包裹即可避免错误的发生:

div(class='div-class', (click)='play()')
div(class='div-class' '(click)'='play()')
<div class="div-class" (click)="play()"></div>
<div class="div-class" (click)="play()"></div>

属性插值

警告:先前版本的Pug/Jade 支持一种插值语法

a(href="/#{url}") Link

如今,这一语法不在被支持,下面会介绍备用方案。

这里有一些备用方案,你可以在属性值中包含变量。

  • 使用JavaScript书写属性:
- var url = 'pug-test.html';
a(href='/' + url) Link
|
|
- url = 'https://example.com/'
a(href=url) Another link
<a href="/pug-test.html">Link</a>
<a href="https://example.com/">Another link</a>
  • 如果你的JavaScript运行时支持ES2015的 template string 功能,你可以使用该语法特性简化你的属性书写方式:
- var btnType = 'info'
- var btnSize = 'lg'
button(type='button' class='btn btn-' + btnType + ' btn-' + btnSize)
|
|
button(type='button' class=`btn btn-${btnType} btn-${btnSize}`)
<button class="btn btn-info btn-lg" type="button"></button>
<button class="btn btn-info btn-lg" type="button"></button>

非转义属性

默认情况下,所有的属性名都将被转移(特殊符号将会使用转义序列代替),为了避免自动转义检测(比载入如跨域脚本的需求),你需要使用特殊的字符,使用 != 替代 =

div(escaped="<code>")
div(unescaped!="<code>")
<div escaped="&lt;code&gt;"></div>
<div unescaped="<code>"></div>

警告:非转义的代码是很费闲的,你必须确保属性值的安全性,避免不安全的跨域脚本的执行。

布尔属性

布尔属性将会以镜像重复的方式被Pug处理,布尔值(true或者false)是被允许的。当属性值没有被执行时,true 值是默认的。

input(type='checkbox' checked)
|
|
input(type='checkbox' checked=true)
|
|
input(type='checkbox' checked=false)
|
|
input(type='checkbox' checked=true.toString())
<input type="checkbox" checked="checked" />
<input type="checkbox" checked="checked" />
<input type="checkbox" />
<input type="checkbox" checked="true" />

如果文档类型是 html , Pug将不会将属性名反映给属性值,而是用最简洁的属性表示方式:

doctype html
|
|
input(type='checkbox' checked)
|
|
input(type='checkbox' checked=true)
|
|
input(type='checkbox' checked=false)
|
|
input(type='checkbox' checked=true && 'checked')
<!DOCTYPE html>
<input type="checkbox" checked>
<input type="checkbox" checked>
<input type="checkbox">
<input type="checkbox" checked="checked">

样式属性

style 属性可以是字符串,类似普通的属性;也可以是对象:

a(style={color: 'red', background: 'green'})
<a style="color:red;background:green;"></a>

类属性

class 属性可以是字符串,类似其他普通的属性;也可以是一个包含类名的数组:

- var classes = ['foo', 'bar', 'baz']
a(class=classes)
|
|
//- the class attribute may also be repeated to merge arrays
a.bang(class=classes class=['bing'])
<a class="foo bar baz"></a>
<a class="foo bar baz bing"></a>

也可以是一个对象,会将类名映射为 true 或者 false 值,对于条件化的类名这是很有用处的:

- var currentUrl = '/about'
a(class={active: currentUrl === '/'} href='/') Home
|
|
a(class={active: currentUrl === '/about'} href='/about') About
<a href="/">Home</a>
<a class="active" href="/about">About</a>

Class字面量

类可以使用 .classname 的语法简写:

a.button
<a class="button"></a>

div 标签被作为通用的选择,因此如果你忽略了标签名,div 将会是默认的标签:

.content
<div class="content"></div>

ID字面量

可以使用 #idname 语法简写:

a#main-link
<a id="main-link"></a>

当忽略标签时,默认的,将使用div标签。

#content
<div id="content"></div>

&attributes(&属性)

发音类似“and attributes”,"&attributes" 语法可以被用来将一个对象放入元素的属性内:

div#foo(data-bar="foo")&attributes({'data-foo': 'bar'})
<div id="foo" data-bar="foo" data-foo="bar"></div>

下方的示例使用对象的字面量,但是你也可以使用一个值为对象的变量。

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

警告:应用了 &attributes 的属性不会自动的转义。你必须确保所有来自用户的输入不会存在不安全的跨域请求问题。


条件判断

case 语句是 JavaScript 中 switch 语句的简写形式,其书写规则如下:

- var friends = 10
case friends
  when 0
    p you have no friends
  when 1
    p you have a friend
  default
    p you have #{friends} friends
<p>you have 10 friends</p>

Case Fall Through

你可以使用 fall through,只需要像在JavaScript中使用 switch 语句那样。

- var friends = 0
case friends
  when 0
  when 1
    p you have very few friends
  default
    p you have #{friends} friends
<p>you have very few friends</p>

与JavaScript语法不同的地方是,JavaScript中的fall through只会出现在 break 语句没有明确的写出时;而在Pug中,它只会发生在块没有被包裹的情况下。

如果你不希望在这种情况下匹配任何条件,只需要添加一个明确的 break

- var friends = 0
case friends
  when 0
    - break
  when 1
    p you have very few friends
  default
    p you have #{friends} friends
//什么也不会输出...,因为当匹配至friends为0时,便直接退出了条件。

Block扩展

Block 扩展的用例:

- var friends = 1
case friends
  when 0: p you have no friends
  when 1: p you have a friend
  default: p you have #{friends} friends
<p>you have a friend</p>

Code

Pug允许在你的模版上书写行内JavaScript代码。这里有三种类型的代码:Unbuffered, Buffered, Buffered 和 Unescaped Buffered。

Unbuffered Code

Unbuffered Code 使用 - 标志开始,它不会在输出内容中添加任何额外的内容。

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

Pug也支持block unbuffered 代码:

-
  var list = ["Uno", "Dos", "Tres",
          "Cuatro", "Cinco", "Seis"]
each item in list
  li= item
<li>Uno</li>
<li>Dos</li>
<li>Tres</li>
<li>Cuatro</li>
<li>Cinco</li>
<li>Seis</li>

Buffered Code

Buffered code 使用 = 标志开始。他将会输出内容,为了安全起见,代码将会被转义。

p
  = 'This code is <escaped>!'
<p>This code is &lt;escaped&gt;!</p>

还可以这样写

p= 'This code is' + ' <escaped>!'
<p>This code is &lt;escaped&gt;!</p>

Unescaped Buffered Code

不希望被转移的buffered代码使用 != 标志开始,类似于JavaScript中的赋值运算并输出结果。非转义的buffered代码不会执行任何转移操作,因此对于用户的输入来说是不安全的:

p
  != 'This code is <strong>not</strong> escaped!'
<p>This code is <strong>not</strong> escaped!</p>

非转义的buffered代码同样可以在单行内书写(同属性一起),并且支支持所有的JavaScript表达式:

p!= 'This code is' + ' <strong>not</strong> escaped!'
<p>This code is <strong>not</strong> escaped!</p>

警告:非转义的buffered代码是非常危险的,你必须确保用户的输入是绝对安全的(避免发生XSS跨域脚本攻击)。

注释

buffered 注释类似于JavaScript中的单行注释,绥中他会以HTML中的注释标签的形式输出:

// just some paragraphs
p foo
p bar
<!-- just some paragraphs-->
<p>foo</p>
<p>bar</p>

Pug也支持unbuffered注释,只需在注释的开头添加一条连字符 - 即可。

这条注释只会在pug代码中显示,不会出现在渲染后的HTML文件中。

//- will not output within markup
p foo
p bar
<p>foo</p>
<p>bar</p>

块级注释

块级注释看起来像这样:

body
  //-
    Comments for your template writers.
    Use as much text as you want.
  //
    Comments for your HTML readers.
    Use as much text as you want.
<body>
  <!--Comments for your HTML readers.
Use as much text as you want.-->
</body>

也就是说,只需要换行并缩进,pug便能识别你希望多行注释。同样块级注释支持是否在HTML中输出注释的选项。

条件注释

Pug在条件注释上没有什么特别的语法。(条件注释是一种为了适配旧版本的IE浏览器而出现的一种特有的方法)

然而,然和以 < 标志开始的一行都会被看作是 plain text,普通的HTML-style 条件注释也能很好的支持。

doctype html

<!--[if IE 8]>
<html lang="en" class="lt-ie9">
<![endif]-->
<!--[if gt IE 8]><!-->
<html lang="en">
<!--<![endif]-->

body
  p Supporting old web browsers is a pain.

</html>
doctype html

<!--[if IE 8]>
<html lang="en" class="lt-ie9">
<![endif]-->
<!--[if gt IE 8]><!-->
<html lang="en">
<!--<![endif]-->

body
  p Supporting old web browsers is a pain.

</html>

条件判断

对于Pug的条件判断语法,是否写 () 是可选择的:

- var user = { description: 'foo bar baz' }
- var authorised = false
#user
  if user.description
    h2.green Description
    p.description= user.description
  else if authorised
    h2.blue Description
    p.description.
      User has no description,
      why not add one...
  else
    h2.red Description
    p.description User has no description
<div id="user">
  <h2 class="green">Description</h2>
  <p class="description">foo bar baz</p>
</div>

Pug同样提供了可选择的 unless 标志,他的意思相当于表示否定的 if,下方的两套代码是等价的。

unless user.isAnonymous
  p You're logged in as #{user.name}
unless user.isAnonymous
  p You're logged in as #{user.name}

文档类型

doctype html
<!DOCTYPE html>

Doctype

doctype html

<!DOCTYPE html>

doctype xml

<!DOCTYPE html>

doctype transitional

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

doctype strict

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

doctype frameset

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

doctype 1.1

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

doctype basic

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">

doctype mobile

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">

doctype plist

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

自定义的文档类型

你可以使用你自己的字面量来自定义文档类型

doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN">

文档类型选项

为了将输出的内容缓存起来,在Pug中,文档类型在某种程度上是会影响编译的,举个例子,无论标签是否自闭合(/>或者>)取决与你的文档类型是HTML还是XML。同样前面提及的布尔属性的效果也会受到影响。

无论出于何种理由,如果只是输出一个HTML片段,那么 doctype 关键词是绝对不能使用的。但是你仍然可以通过文档类型选项的方式指定你希望该HTML碎片遵守的文档类型:

var pug = require('pug');

var source = 'img(src="foo.png")';

pug.render(source);
// => '<img src="foo.png"/>'

pug.render(source, {doctype: 'xml'});
// => '<img src="foo.png"></img>'

pug.render(source, {doctype: 'html'});
// => '<img src="foo.png">'

上一篇《Eloquent JavaScript译文第二版 / 数值》

下一篇《ES6 promises特性来自javascript走心的承诺》

永久链接 http://www.shuaihua.cc/article/have-pug-template-engine-see-this-article

快速跳转 心头好文 - language - 《完全掌握Pug模版引擎看这篇就够了》

发布日期 2017-10-31 12:12:8 周二

版权声明 自由转载-非商用-非衍生-保持署名(创意共享3.0许可证