Pug快速入门

参考文档:

什么是PUG?

PUG原名JADE,是一个高性能html语言模板引擎,用于Node.js和浏览器环境,使用JavaScript实现。pug不仅功能强大,最重要的是它真的非常简单,只需要一点html和 javascript基础就能在一小时内上手使用。pug学习成本极低、效率高、功能强大的特点得到了众多开发者的喜爱。

原生html存在的痛点

  • 纯静态,没有动态变量的概念
  • 不能复用,没有组件概念,每个页面对应一个html文件
  • 当html结构较深,代码多的时候或者没有规范的换行缩进会使代码看的十分杂乱,让人摸不着头绪,难以维护和排查问题

pug的特点

而Pug是简洁、对空格敏感的语法,抛弃了原生html尖括号和闭合标签,使用换行+缩进来表示嵌套关系,让你在写html时也像写python代码一样流畅自然!

以下是pug官网的一个简单示例:

doctype html
html(lang="en")
  head
    title= pageTitle
    script(type='text/javascript').
      if (foo) bar(1 + 5);
  body
    h1 Pug - node template engine
    #container.col
      if youAreUsingPug
        p You are amazing
      else
        p Get on it!
      p.
      	Pug is a terse and simple templating language with a
        strong focus on performance and powerful features.

pug将上述代码转换为:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Pug</title>
    <script type="text/javascript">
      if (foo) bar(1 + 5);
    </script>
  </head>
  <body>
    <h1>Pug - node template engine</h1>
    <div id="container" class="col">
      <p>You are amazing</p>
      <p>
        Pug is a terse and simple templating language with a strong focus on
        performance and powerful features.
      </p>
    </div>
  </body>
</html>

对比之下可以看到,PUG的优势在于其语法的简洁性,省去了html的闭合标签,通过换行缩进来表示嵌套关系,极大的减少了代码量,并且,pug有其自己的语法,拥有循环、条件控制、定义变量、代码块复用等功能。可以说当你在写pug模板的同时,也在写Javascript,当你习惯了其语法规则后,可以显著提升你编写html代码的效率。

Pug十分钟上手

在本章,我们先对Pug的语法特点进行精炼的介绍,点出其与javascript语言以及原生html语言的不同之处,关于pug语法的详细教程可能在后面分章节更新~

使用Javascript

Pug 为您在模板中嵌入 JavaScript 提供了可能。主要有三种类型的代码。

  • - 开始的行不直接进行输出的代码,可以在这行执行javascript 表达式
  • = 开始的行表示带有输出的代码,它应该是可以被求值的一个 JavaScript 表达式,为安全起见,它将被 HTML 转义。
  • != 开始的行代表不转义的,带有输出的代码。这将不会做任何转义,所以用于执行用户的输入将会不安全

编译前:

- for (var x = 0; x < 3; x++)
  li item
  
  p= '这个代码被 <转义> 了!'
  
  p!= '这段文字' + ' <strong>没有</strong> 被转义!'

编译后:

<li>item</li>
<li>item</li>
<li>item</li>

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

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

变量

在Pug中,你可以使用-var来声明一个变量,且无需考虑变量类型,类似于原生JavaScript中的声明变量。你可以在该变量的作用域内任意使用此变量,包括赋值、修改、引用、传参等等。

在Pug中,每一格缩进就代表一个新的作用域,作用域之间存在上下级关系,其机制基本与java、python等常用语言相同,你可以获取同级或上级作用域中的变量,但是无法获取子作用域的变量。通过下面这个例子,相信你可以很快理解Pug中的变量及作用域问题。

var a = 1
var b = 2
var c = 3

body
    -let d = 4 // d是处于body 作用域内的变量,和他同级或它的子级可以找到他
    div
        p=d // 可以从上层作用域找到d
        p=a // 可以从顶级作用域找到a
        p=e // undefined 不会输出任何内容 与JS相同,e还没有被赋值
        - var e = 5 
        ul
			while e > 0 // 这里会迭代5次, 产生5个作用域
                - e--
                - const f = 10 + e // f是 while循环语句作用域的变量 上层作用域拿不到它
                li = f

属性Attribute

标签属性和 HTML 语法非常相似。

  • 你可以用空格、逗号、逗号+空格三种方法作为属性分隔符,或者将多个属性换行写。
  • 属性的值可以是所有的JavaScript表达式
  • 类可以使用.classname语法来定义
  • ID可以使用#idname来定义

不同的属性分隔方法

编译前:

a(href='baidu.com') 百度
a(class='button' href='baidu.com') 百度
a(class='button', href='baidu.com') 百度

//所有的javascript表达式都能使用
- var authenticated = true
body(class=authenticated ? 'authed' : 'anon')

//多行属性
input(
  type='checkbox'
  name='agreement'
  checked
)

//不转义的属性
div(escaped="<code>")
div(unescaped!="<code>")

编译后:

<a href="baidu.com">百度</a>
<a class="button" href="baidu.com">百度</a>
<a class="button" href="baidu.com">百度</a>

<body class="authed"></body>

<input type="checkbox" name="agreement" checked="checked" />

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

类属性

类可以使用 .classname 语法来定义,考虑到使用 div 作为标签名这种行为实在是太常见了,所以如果您省略掉标签名称的话,div就是默认值:

编译前:

a.button(href="baidu.com")

.content

编译后:

<a class="button" href="baidu.com"></a>

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

ID属性

D 可以使用 #idname 语法来定义,与class相同,考虑到使用 div 作为标签名这种行为实在是太常见了,所以如果你省略掉标签名称的话,div就是默认值:

编译前:

a#main-link(href="baidu.com")

#content

编译后:

<a id="main-link" href="baidu.com"></a>

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

条件控制与迭代

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 用户没有描述

编译后:

<div id="user">
  <h2 class="green">描述</h2>
  <p class="description">foo bar baz</p>
</div>

条件分支case

case也就是JavaScript语句中的switch,在case语句中,可以像 JavaScript 中的 switch 语句那样使用传递(fall through)。不同之处在于,在 JavaScript 中,传递会在明确地使用 break 语句之前一直进行。而在 Pug 中则是,传递会在遇到非空的语法块前一直进行下去。在某些情况下,如果您不想输出任何东西的话,您可以明确地加上一个原生的 break 语句:

编译前:

- var friends = 0
case friends
  when 0
  when 1
    p 您的朋友很少
  default
    p 您有 #{friends} 个朋友

编译后:

<!-- 这里发生了传递! -->
<p>您的朋友很少</p>

迭代

Pug 目前支持两种主要的迭代方式: eachwhile。这里主要介绍each,这是Pug头等的迭代方式,功能十分强大,最推荐使用。当然while也常用于创建一个简单循环。

在Pug中,你可以很方便的获取迭代对象的索引和键值:

编译前:

ul
  each val in [1, 2, 3, 4, 5]
    li= val
    
ul
  each val, index in ['〇', '一', '二']
    li= index + ': ' + val
    
ul
  each val, index in {1:'一',2:'二',3:'三'}
    li= index + ': ' + val

编译后:

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>

<ul>
  <li>0: 〇</li>
  <li>1: 一</li>
  <li>2: 二</li>
</ul>

<ul>
  <li>1: 一</li>
  <li>2: 二</li>
  <li>3: 三</li>
</ul>

用于迭代的对象或数组仅仅是个 JavaScript 表达式,因此它可以是变量、函数调用的结果,又或者其他的什么东西。您还能添加一个 else 块,这个语句块将会在数组与对象没有可供迭代的值时被执行。下面这两个例子的作用是等价的:

编译前:

- var values = [];
ul
  each val in values.length ? values : ['没有内容']
    li= val
    
//与上面的例子等价    
- var values = [];
ul
  each val in values
    li= val
  else
    li 没有内容

编译后:

<ul>
  <li>没有内容</li>
</ul>

结语

看到这里,你应该已经对Pug语言有了一定的了解了,现在你应当理解为什么之前会说写Pug就像写JavaScript一样了,因为它们真的很像!你可以随意的使用变量声明与条件控制语句,相当于同时在编写Html和JavaScript代码,