Pug模板 #

一、Pug简介 #

1.1 什么是Pug? #

Pug(原名Jade)是一个高性能的模板引擎,使用缩进来表示嵌套关系,语法简洁优雅。

1.2 特点 #

  • 缩进式语法,无需闭合标签
  • 支持模板继承
  • 支持Mixins
  • 可扩展性强

1.3 安装 #

bash
npm install pug

二、基本配置 #

2.1 设置视图引擎 #

javascript
const express = require('express');
const app = express();

app.set('view engine', 'pug');
app.set('views', './views');

三、Pug语法 #

3.1 标签 #

pug
html
    head
        title 页面标题
    body
        h1 标题
        p 段落内容

编译为:

html
<html>
    <head>
        <title>页面标题</title>
    </head>
    <body>
        <h1>标题</h1>
        <p>段落内容</p>
    </body>
</html>

3.2 属性 #

pug
a(href='/home', class='link', target='_blank') 首页
input(type='text', name='username', placeholder='用户名')
div#main.container.active

编译为:

html
<a href="/home" class="link" target="_blank">首页</a>
<input type="text" name="username" placeholder="用户名">
<div id="main" class="container active"></div>

3.3 文本 #

pug
p 普通文本
p.
    多行文本
    第二行
    第三行
p
    | 文本行1
    | 文本行2
    strong 加粗文本

3.4 变量输出 #

pug
h1= title
p= message
p 欢迎, #{user.name}
p 年龄: #{user.age || '未知'}

3.5 属性中使用变量 #

pug
a(href=url) 链接
a(href='/user/' + userId) 用户详情
input(value=defaultValue)
div(class=isActive ? 'active' : 'inactive')

四、条件语句 #

4.1 if/else #

pug
if user
    p 欢迎, #{user.name}
else
    p 请登录

if user.role === 'admin'
    p 管理员面板
else if user.role === 'editor'
    p 编辑面板
else
    p 用户面板

4.2 unless #

pug
unless user
    p 请先登录

4.3 case #

pug
case status
    when 'active'
        p 激活
    when 'inactive'
        p 未激活
    default
        p 未知状态

五、循环语句 #

5.1 each #

pug
ul
    each user in users
        li= user.name

each user, index in users
    p #{index + 1}. #{user.name}

5.2 for #

pug
- for (let i = 0; i < items.length; i++)
    p= items[i]

5.3 while #

pug
- let n = 0
while n < 5
    p= n++

六、代码 #

6.1 单行代码 #

pug
- const name = '张三'
- const age = 25
p= name

6.2 多行代码 #

pug
-
    const users = [
        { name: '张三', age: 25 },
        { name: '李四', age: 30 }
    ]
    const total = users.length

七、包含文件 #

7.1 include #

pug
include header.pug
include partials/nav.pug

main
    h1 内容区域

include footer.pug

7.2 包含其他类型文件 #

pug
style
    include style.css
script
    include script.js

八、模板继承 #

8.1 定义布局 #

views/layout.pug:

pug
doctype html
html
    head
        title= title
        block head
    body
        include partials/header
        block content
        include partials/footer
        block scripts

8.2 继承布局 #

views/index.pug:

pug
extends layout

block head
    link(rel='stylesheet', href='/css/home.css')

block content
    h1 首页
    p 欢迎来到网站

block scripts
    script(src='/js/home.js')

8.3 追加/前置 #

pug
extends layout

block append head
    link(rel='stylesheet', href='/css/custom.css')

block prepend scripts
    script(src='/js/common.js')

九、Mixins #

9.1 定义Mixin #

pug
mixin userCard(user)
    .user-card
        h3= user.name
        p= user.email
        span= user.role

9.2 使用Mixin #

pug
each user in users
    +userCard(user)

9.3 带属性的Mixin #

pug
mixin link(href, name)
    a(href=href)&attributes(attributes)= name

+link('/home', '首页')
+link('/about', '关于')(class='nav-link', target='_blank')

9.4 块级Mixin #

pug
mixin article(title)
    article
        h2= title
        if block
            block
        else
            p 无内容

+article('标题')
    p 这是文章内容

十、完整示例 #

10.1 布局文件 #

views/layout.pug:

pug
doctype html
html(lang='zh-CN')
    head
        meta(charset='UTF-8')
        meta(name='viewport', content='width=device-width, initial-scale=1.0')
        title= title + ' - ' + siteName
        link(href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css', rel='stylesheet')
        block styles
    body
        nav.navbar.navbar-expand-lg.navbar-dark.bg-dark
            .container
                a.navbar-brand(href='/')= siteName
                .navbar-collapse
                    ul.navbar-nav
                        li.nav-item
                            a.nav-link(href='/') 首页
                        li.nav-item
                            a.nav-link(href='/users') 用户
                        li.nav-item
                            a.nav-link(href='/posts') 文章
        
        .container.mt-4
            if messages.error
                .alert.alert-danger= messages.error
            if messages.success
                .alert.alert-success= messages.success
            
            block content
        
        footer.bg-dark.text-light.py-4.mt-5
            .container.text-center
                p &copy; 2024 #{siteName}
        
        script(src='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js')
        block scripts

10.2 用户列表页面 #

views/users/index.pug:

pug
extends ../layout

block content
    .d-flex.justify-content-between.align-items-center.mb-4
        h2 用户列表
        a.btn.btn-primary(href='/users/new') 添加用户
    
    table.table.table-striped
        thead
            tr
                th ID
                th 用户名
                th 邮箱
                th 角色
                th 创建时间
                th 操作
        tbody
            each user in users
                tr
                    td= user.id
                    td= user.name
                    td= user.email
                    td
                        span.badge(class=user.role === 'admin' ? 'bg-danger' : 'bg-primary')= user.role
                    td= formatDate(user.createdAt)
                    td
                        a.btn.btn-sm.btn-info(href='/users/' + user.id) 查看
                        a.btn.btn-sm.btn-warning(href='/users/' + user.id + '/edit') 编辑
                        form.d-inline(action='/users/' + user.id + '?_method=DELETE', method='POST')
                            button.btn.btn-sm.btn-danger(type='submit', onclick='return confirm("确定删除?")') 删除
    
    if totalPages > 1
        nav
            ul.pagination.justify-content-center
                if currentPage > 1
                    li.page-item
                        a.page-link(href='/users?page=' + (currentPage - 1)) 上一页
                
                - for (let i = 1; i <= totalPages; i++)
                    li.page-item(class=currentPage === i ? 'active' : '')
                        a.page-link(href='/users?page=' + i)= i
                
                if currentPage < totalPages
                    li.page-item
                        a.page-link(href='/users?page=' + (currentPage + 1)) 下一页

10.3 Mixins文件 #

views/mixins/user.pug:

pug
mixin userCard(user)
    .card.mb-3
        .card-body
            h5.card-title= user.name
            h6.card-subtitle.mb-2.text-muted= user.email
            p.card-text
                span.badge.bg-primary= user.role
            a.card-link(href='/users/' + user.id) 查看详情

mixin pagination(currentPage, totalPages, baseUrl)
    if totalPages > 1
        nav
            ul.pagination.justify-content-center
                if currentPage > 1
                    li.page-item
                        a.page-link(href=baseUrl + '?page=' + (currentPage - 1)) 上一页
                
                - for (let i = 1; i <= totalPages; i++)
                    li.page-item(class=currentPage === i ? 'active' : '')
                        a.page-link(href=baseUrl + '?page=' + i)= i
                
                if currentPage < totalPages
                    li.page-item
                        a.page-link(href=baseUrl + '?page=' + (currentPage + 1)) 下一页

10.4 使用Mixins #

pug
include mixins/user

extends layout

block content
    h2 用户卡片
    
    each user in users
        +userCard(user)
    
    +pagination(currentPage, totalPages, '/users')

十一、总结 #

Pug要点:

语法 说明
缩进 表示嵌套关系
= 输出变量
#{} 插值输出
extends 继承模板
block 定义区块
include 包含文件
mixin 定义可复用块

下一步,让我们学习静态文件服务!

最后更新:2026-03-28