唠唠闲话

暑假在家搭建了博客网站 (看这里),通过博客写作进行技术积累。

目前写了差不多 20 篇,没搞 SEO 收录,也没做阅读统计,网站主要自己用。

最近打算把网站公开,一些原本懒得弄的设置,都要补上。

博客用的是 Butterfly 主题,高级的“魔改”方案要修改配置文件,即 *.pug 文件。

这篇就聊聊 pug 的基本语法。

pug

pug 模板引擎, 之前也叫 jade 模板引擎. 用来做服务端渲染常用的一种模板引擎。

参考文章

CSDN:网页模板 pug 基本语法
CSDN:pug 的安装和编译
CSDN:pug 模板引擎语法学习和记录


安装和编译

  1. 安装很简单,输入下边命令
1
2
npm install pug # 安装插件
npm install -g pug-cli # 编译工具
  1. 编译语法如下
    1
    pug -P <文件/文件夹>

基础内容

语法

pug 不同于 html,前者不需要标签的开和闭,如 html 的 <p>Demo</p>,在 pug 使用 p Demo 即可。

缩进

pug 对空格敏感,有点类似 python 对制表符 tab 敏感。pug 使用空格作为缩进符。同一级标签需保证左对齐。

示例:

1
2
3
div
p Hello, world!
p Hello, pug.

渲染结果:

1
2
3
4
<div>
<p>Hellow, world!</p>
<p>Hello, pug.</p>
</div>

注释

pug 使用 //-// 对代码进行注释,前者注释内容不出现在渲染后的 html 文件中,后者反之。

示例:

1
2
//- html中不包含此行
// html中会包含此行,作为注释

渲染结果:

1
2

<!-- html中会包含此行-->

属性

pug 将标签属性存放于括号()内,多个属性之间以逗号或空格分隔。此外,对于标签的 idclass,pug 使用 # 紧跟标签 id ,使用 . 紧跟标签的 class,可以同时设置多个 class

示例:

1
2
h1#title Test title
img#name.class1.class2(src="/test.png" alt="test")

渲染效果:

1
2
<h1 id="title">Test title</h1>
<img id="name" class="class1 class2" src="/test.png" alt="test">

包含

为了方便代码复用,pug 提供了 include 包含功能,以下代码会将_partial 目录下的 head.pug 文件内容包含到当前调用的位置。类似与 LaTeX 的 \input

示例:

1
2
3
doctype html
html(lang='en')
include _partial/head.pug

较复杂内容

继承

下面是一个简单的 base 模板,通过 block 定义了页面头部 head 和内容 body 。块 block 有点类似 C/C++ 的抽象函数,需要在继承者中完成定义,填充具体内容。

1
2
3
4
5
6
//- base.pug
html
head
block title
body
block content

以下文件使用 extends 继承以上模板,通过 block 覆盖或替换原有块 block 。当然,继承者也可以在原有基础上继续扩展。

示例:

1
2
3
4
5
6
7
8
9
//- index.pug
extends base.pug

block title
title "Test title"

block content
h1 Hello world!
block article

等效于:

1
2
3
4
5
6
html
head
title "Test title"
body
h1 Hello world!
block article

渲染效果:

1
2
3
4
5
6
7
8
<html>
<head>
<title>"Test title"</title>
</head>
<body>
<h1>Hello world!</h1>
</body>
</html>

变量

pug 中通过 - var name = value- let name = value 的形式定义变量和变量赋值。

需注意的是,在引用变量时,需要在引用位置加上 = 号,否则会默认将变量名当成普通字符串使用。

错误示例

1
2
- var test = 1
p 1+test

效果:

1
<p>1+test</p>

正确示例

1
2
- var test = 1
p= 1+test

效果:

1
<p>2</p>

标签 p 后追加 =,后续的字符串按变量看待。

转义

如果想要将变量与其它字符串常量或是变量连接在一起,就不能用等号了,而是应该用#{},该符号会对大括号内的变量进行求值和转义,最终得到渲染输出的内容。

示例:

1
2
3
4
- var girl = 'Lily'
- var boy = 'Jack'
p #{girl} is so beautiful!
p And #{boy} is handsome.

效果

1
2
<p>Lily is so beautiful!</p>
<p>And Jack is handsome.</p>

条件结构

pug 的条件语句与其它语言类似,均是如下这般:

1
2
3
4
5
6
7
8
- var A = {value: 'Test'}
- var B = true
if A.value
p= A.value
else if B
p= B
else
p nothing

效果:

1
<p>Test</p>

迭代

pug 中使用 each 和 while 实现循环迭代,each 可以返回当前所在项的索引值,默认从 0 开始计数。

each

示例(第二参数 index 可不加):

1
2
3
4
5
//- get index of each
- var week = ['Sun', 'Mon', 'Tus', 'Wen', 'Thu', 'Fri', 'Sat']
ol
each item, index in week
li= index + ':' + item

效果:

1
2
3
4
5
6
7
8
9
<ol>
<li>0:Sun</li>
<li>1:Mon</li>
<li>2:Tus</li>
<li>3:Wen</li>
<li>4:Thu</li>
<li>5:Fri</li>
<li>6:Sat</li>
</ol>

while

while 调用方式如下:

1
2
3
4
5
//- while
- var day = 1
ul
while day < 7
li= day++

效果:

1
2
3
4
5
6
7
8
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>

for

for 调用示例如下:

1
2
3
ul
- for(var i=1;i<7;i++)
li #{i}

效果同 while。

逻辑运算

逻辑运算结合 ? 可以实现条件赋值。

示例:

1
2
3
4
5
6
7
- let res1 = (false || true) ? 'a' : 'b'
- let res2 = (false && true) ? 'a' : 'b'
- let res3 = !(false && true) ? 'a' : 'b'

p= res1
p= res2
p= res3

效果:

1
2
3
<p>a</p>
<p>b</p>
<p>a</p>

Mixin

用作函数

mixin 名曰混入,类似其它编程语言中的函数,也是为了代码复用,可带参数或不带参数,定义方式如下:

1
2
3
4
mixin menu-item(href, name)
li
span.dot
a(href=href)= name

其中,menu-item 为调用时所用名称,可认为是函数名,hrefname 是参数。同上定义变量所说,a(href=href)= name 中第二个 = 是为了将后面的name当作参数来处理,而不是当作字符串 “name” 来处理。

调用 mixin 定义的代码块,需通过 + 号紧跟 mixin 名称及参数:

1
2
+menu-item('/Archives','Archives')
+menu-item('/About','About')

效果:

1
2
<li><span class="dot"> </span><a href="/Archives">Archives</a></li>
<li><span class="dot"> </span><a href="/About">About</a></li>

混合使用

(这部分不理解)
mixin 之所以称为混入,是因为其语法不局限于函数调用,在 mixin 可以使用块 block

1
2
3
4
5
6
7
8
9
10
mixin print(post)
if block
block
else
p= post

+print("no block")
+print("")
div.box
p this is the content of block

效果:

1
2
<p>no block</p>
<div class="box"><p>this is the content of block</p></div>

JavaScript

注意以下 pug 语句中第一行的 . 号。

1
2
3
4
5
6
7
script(type='text/javascript').
var data = "Test"
var enable = true
if enable
console.log(data)
else
console.log('nothing')

效果

1
2
3
4
5
6
7
8
<script type='text/javascript'>
var data = "Test"
var enable = true
if enable
console.log(data)
else
console.log('nothing')
</script>

对于简单脚本,使用 pug 尚可,复杂的还是单独写到 .js 文件中,然后通过 pug 引用方便一些,引用方式如下:

1
script(type='text/javascript', src='/path/to/js')

hexo 相关

在 hexo 主题中使用 pug 时,可以通过使用 hexo 提供的全局变量config,theme 来分别调用博客根目录下 _config.yml 文件中的参数以及主题根目录下 _config.yml 文件中的参数。

1
2
3
4
5
//- blog config
p= config.description

//- theme config
p= theme.title

当然,pug 中可以直接使用 hexo 提供的其它全局变量及辅助函数,使用方法详见 hexo 的文档

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
//- head.pug
head
meta(http-equiv='content-type', content='text/html; charset=utf-8')
meta(content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0', name='viewport')
meta(content='yes', name='apple-mobile-web-app-capable')
meta(content='black-translucent', name='apple-mobile-web-app-status-bar-style')
meta(content='telephone=no', name='format-detection')
meta(name='description', content=config.description)
block title
link(rel='stylesheet', type='text/css', href=url_for(theme.css) + '/style.css' + '?v=' + theme.version)
link(rel='Shortcut Icon', type='image/x-icon', href=url_for('favicon.png'))
script(type='text/javascript', src='//cdn.bootcss.com/jquery/3.3.1/jquery.min.js')
block more
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//- base.pug
doctype html
html(lang='en')
include _partial/head.pug
block more
link(rel='stylesheet', type='text/css', href=url_for(theme.plugins) + '/prettify/doxy.css')
script(type='text/javascript', src=url_for(theme.js) + '/ready.js' + '?v=' + theme.version, async)

//- body
body: #container.box
.h-wrapper
include _partial/nav-menu.pug
// article content
block content

include _partial/footer.pug

其中:

  • theme.* 为主题配置文件 _config.yml 中的参数
  • url_for 为 hexo 提供的用于查找资源路径的函数

总结

pug 提供了包含,继承,Mixin 等多种方式用于代码复用,语法简洁易懂,除了初学时需花费一些时间学习各种标点符号的含义外,其它倒也没有太大困难。

当然啦,pug 还有许多其它特性,但就我目前使用情况而言,以上这些便已足够。