
Pug 哈巴狗 | 便捷的HTML预处理器 一
文章目录
- [Pug 哈巴狗 | 便捷的HTML预处理器 一](#Pug 哈巴狗 | 便捷的HTML预处理器 一)
-
- 一、有没有必要使用Pug
- 二、如何使用Pug
-
- [2.1 命令行](#2.1 命令行)
- [2.2 API 编译](#2.2 API 编译)
-
- [2.2.1 选项 Options](#2.2.1 选项 Options)
- [2.2.2 pug.compile(source, ?options): returns](#2.2.2 pug.compile(source, ?options): returns)
- [2.2.3 pug.compileFile(path, ?options): returns](#2.2.3 pug.compileFile(path, ?options): returns)
- [2.2.4 pug.compileClient(source, ?options): returns](#2.2.4 pug.compileClient(source, ?options): returns)
- [2.2.5 pug.compileClientWithDependenciesTracked(source, ?options): returns](#2.2.5 pug.compileClientWithDependenciesTracked(source, ?options): returns)
- [2.2.6 pug.compileFileClient(path, ?options): returns](#2.2.6 pug.compileFileClient(path, ?options): returns)
- [2.2.7 pug.render(source, ?options, ?callback): returns](#2.2.7 pug.render(source, ?options, ?callback): returns)
- [2.2.8 pug.renderFile(path, ?options, ?callback): returns](#2.2.8 pug.renderFile(path, ?options, ?callback): returns)
- 三、基础语法
-
- [3.1 标签](#3.1 标签)
- [3.2 纯文本](#3.2 纯文本)
- [3.3 属性](#3.3 属性)
- [3.4 注释](#3.4 注释)
- [3.5 循环迭代](#3.5 循环迭代)
- [3.6 条件分支](#3.6 条件分支)
- [3.7 代码嵌入](#3.7 代码嵌入)
- 四、进阶语法
-
- [4.1 包含注入](#4.1 包含注入)
- [4.2 Mixin混入](#4.2 Mixin混入)
- [4.3 模板继承](#4.3 模板继承)
- 参考资料💘
- 推荐博文🍗
一、有没有必要使用Pug
与 Scss、Less 类似,Pug 本质上也是一个预处理器,为了提高编写 HTML 代码的效率而诞生,对比实现相同内容的 HTML 代码来讲,Pug 代码更短更精简,同时一定程度上提高代码阅读性与可维护性。
Pug 废弃使用标签箭头括号开始、闭合的书写方式,对于正常书写 HTML 多层次嵌套关系在错误操作下破坏某个代码块结构起到很好的保护作用。
Pug 曾用名叫"Jade",但后来发现此名称是一个已经被注册过的商标,因为版权问题从而改名成"Pug"。**可以将 Pug 说成一个语言,但这个语言没有自己的编译器或则是解释器,需要依赖其他语言进行编译(简单理解可以是寄生者与宿主的关系),编译的最终结果还是 HTML。**因为是属于 Web 前端内的东西,目前主流宿主使用的是 NodeJS,当然像 C#、Python、Java 这些都是被支持的,本文也将会以 NodeJs 作为宿主对 Pug 进行讲解,具体文档请查阅此处:Pug 模板引擎简介 | Pug 模板引擎中文文档 | Pug中文网
以上是对于 Pug 的说明了解,对于是否要使用 Pug,这个问题争议的比较大,争议的焦点总结下来主要是以下三种:
- 需要额外的学习成本,相比较 Sass、Less 而言,Pug 与 HTML 之间的语法变化较大,对于大多数人来讲,提高开发效率的学习成本远没有复制粘贴多几个HTML代码来的快。
- 可移植性差,对于使用前端Web框架项目,语法功能重复度较高,在编写 Pug 代码基础上需要兼容原有框架语法,同时需要额外依赖包支持。
- 因为最终结果需要的是 HTML,Pug 只是一个在开发过程中使用到的预处理器,每次模板更新时需要重新编译,这在某些大型项目中可能造成额外的性能开销,尤其是在模板非常复杂时,同时 Pug 的编译性能并不优秀 ,这种编译步骤会影响构建和渲染速度。虽然对 Pug 自身的语法错误在编译的时候有一定错误提示打印,但对于 Pug 支持嵌入的 JavaScript 代码语法错误,提示就很不友好了,这造成一定程度上的调试困难。
除了第三点对于编译性能的优化难处理,克服了前两种问题之后,使用 Pug 能够确确实实的提高开发效率,对于时间短任务重或则是小型项目这一类型需求来说还是挺不错的。
二、如何使用Pug
Pug 有两种编译方式,一种是通过命令行,一种是通过编写代码引入 Pug 编译器依赖通过其 API 解析 pug 文件并将其导出,使用命令行就可满足大多数需求。
2.1 命令行
| 管理工具 | 命令 |
|---|---|
| npm | npm i pug-cli -g |
| yarn | yarn global add pug-cli |
| pnpm | pnpm global add pug-cli |
| 命令选项 | 描述 |
|---|---|
| -h, --help | 查看帮助文档 |
| -V, --version | 查看版本号 |
| -O, --obj <str|path> | 指定编译配置项的 JSON/JavaScript文件路径或对象 |
| -o, --out | 输出编译后HTML文件路径地址,默认为当前目录 |
| -p, --path | 用于解析包含的文件名 |
| -b, --basedir | 指定解析所用的文件根目录 |
| -P, --pretty | 是否格式化输出的HTML代码,默认将压缩为一行 |
| -c, --client | 使用客户端runtime.js的编译函数 |
| -n, --name | 编译模板的名称,需配合--client使用 |
| -D, --no-debug | 不使用debug模式编译,速度更快 |
| -w, --watch | 是否启用热编译,在文件更改时自动编译生成结果 |
| -E, --extension | 指定输出文件的扩展名 |
| -s, --silent | 静默式编译,将不会打印日志信息 |
| --name-after-file | 以文件名命名模板名称,需配合--client使用 |
| --doctype | 在命令行上指定文档类型(如果有用的话),可选值 "HTML"、"xml"等,具体请查阅:[Doctype |
bash
# 单个文件编译
pug foo.pug -P
pug foo.pug -o ./dist -P
# 多文件可用空格区分
pug foo.pug bar.pug ./pug/too.pug -P
# 若路径不带后缀,则认定其为目录并渲染目录下的所有文件
pug ./dir
pug ./dir -o ./dir/dist -P
# 指定编译根目录
pug foo.pug -b ./root -P
# 热更新模式,对多个文件、文件夹也同样适用
pug foo.pug -w
pug foo.pug bar.pug -w
pug ./dir -w
# 使用编译配置项设置
pug -O '{"doctype": "HTML"}' foo.pug
pug -O options.json foo.pug
2.2 API 编译
| 管理工具 | 命令 |
|---|---|
| npm | npm i pug -D |
| yarn | yarn add pug -D |
| pnpm | pnpm add pug -D |
javascript
// 文件名 pug.js
const fs = require("fs");
const path = require("path");
const pug = require("pug");
const BASE_DIR = __dirname;
const IN_PATH = path.join(BASE_DIR, "../pug/foo.pug");
const OUT_PATH = path.join(BASE_DIR, "../pug/dist/foo.HTML");
const options = {
pretty: true,
}
// 读取PUG文件
const compiled = pug.compileFile(IN_PATH, options);
// 编译并写入HTML文件中
fs.writeFileSync(OUT_PATH, compiled())
在控制台中执行此命令运行该脚本
bash
node pug.js
Tips:仅使用命令行方式,此依赖并不是并要的。
2.2.1 选项 Options
所有的 API 方法都可以使用以下选项,也可适用于命令行。
| 选项名 | 类型 | 描述 |
|---|---|---|
| filename | string | 要编译的代码的文件名。用于异常信息以及(使用相对路径的)包含(include)和扩展(extends)操作。默认值是 'Pug'。 |
| basedir | string | 模板里所有绝对定位的根目录。 |
| doctype | string | 如果 doctype 没有出现模板里(比如模板只渲染一个 HTML 片段),那么您可以在这里指定它。在一些需要控制自闭合标签和布尔值属性的代码样式的时候非常有用。您可以阅读 doctype 的说明来了解更多细节。 |
| pretty | boolean | string |
| filters | object | 存放自定义过滤器的哈希表。默认为 undefined。 |
| self | boolean | 是否使用一个叫做 self 的命名空间来存放局部变量。这可以加速编译的过程,但是,相对于原来书写比如 variable 来访问局部变量,您将需要改为 self.variable 来访问它们。默认为 false。 |
| debug | boolean | 当设置为 true 时,编译产生的函数代码会被记录到标准输出。 |
| compileDebug | boolean | 当设置为 true 时,源代码会被包含在编译出来的模板函数中,用于提供更详实的错误信息(这在开发时会有用)。它默认是启用的,除非是在 Express 的生产环境模式中。 |
| globals | Array | 该数组用于向模板中添加全局对象的名字,编译器将保证它们不被局部作用域影响。 |
| cache | boolean | 当设置为 true 时,编译出来的函数会被缓存下来。此时必须填写 filename 选项作为缓存的索引字段。该选项仅用于 render 函数。默认为 false。 |
| inlineRuntimeFunctions | boolean | 相对于使用 require 来获得公用的运行时函数,是否需要直接嵌入这些运行时函数。在 compileClient 函数里默认是 true,因此就不需要再手动包含那些函数(从而让其能在浏览器上运行)。在其他的 compile / render 系列函数中,默认是 false。 |
| name | string | 模板函数的名称。仅用于 compileClient 函数。默认值是 'template'。 |
2.2.2 pug.compile(source, ?options): returns
把一个 Pug 模板编译成一个可多次使用、可传入不同局部变量渲染的函数。
- source :string
需要编译的 Pug 代码,注意是编写代码的字符串,而不是文件路径。 - options :object
选项对象。 - returns :function
一个可以从包含局部变量的对象渲染生成出 HTML 的函数。
2.2.3 pug.compileFile(path, ?options): returns
从文件中读取一个 Pug 模板,并编译成一个可多次使用、可传入不同局部变量渲染的函数。
- path :string
需要编译的 Pug 代码文件的位置。 - options :object
选项对象。 - returns :function
一个可以从包含局部变量的对象渲染生成出 HTML 的函数。
2.2.4 pug.compileClient(source, ?options): returns
把一个 Pug 字符串模板编译成一份 JavaScript 代码字符串,通常将生成的 JavaScript 字符串代码写入到新JS文件中,并将其引用。
- source :string
需要编译的 Pug 代码。 - options :object
选项对象。 - returns :string
一份 JavaScript 代码字符串。
javascript
const fs = require('fs');
const pug = require("pug");
// 编译出一个函数
const fn = pug.compileClient('string of pug', options);
// 渲染并写入JS文件
// => 'function template(locals) { return "从 Pug 生成的 HTML 代码"; }'
fs.writeFileSync("foo.js", fn(locals));
此方法提供给用户端使用,大多数情况下并不会用到。
2.2.5 pug.compileClientWithDependenciesTracked(source, ?options): returns
此方法大多用于编写自动化脚本、分析Pug代码内容,监视文件变动时用到,用法与 pug.<font style="color:rgb(28, 30, 33);">compileClient</font>方法一样,只不过返回值是以结构树对象的形式返回。
json
{
'body': 'function (locals) {...}',
'dependencies': ['filename.pug']
}
此方法提供给用户端使用,大多数情况下并不会用到。
2.2.6 pug.compileFileClient(path, ?options): returns
与 pug.<font style="color:rgb(28, 30, 33);">compileClient</font>方法一样,不同的是从文件里读取内容。
此方法提供给用户端使用,大多数情况下并不会用到。
- path :string
需要编译的 Pug 代码文件的位置。
此方法提供给用户端使用,大多数情况下并不会用到。
2.2.7 pug.render(source, ?options, ?callback): returns
直接渲染 Pug 代码字符串并将生成的 HTML 结果返回。
- source :string
需要渲染的 Pug 代码。 - options :object
选项对象。 - callback :function
Node.js 风格的回调函数,用于接收渲染结果。注意:这个回调是同步执行的。 - returns :string
渲染出来的 HTML 字符串。
javascript
const pug = require('pug');
// => '<div>string of pug</div>'
const HTML = pug.render(`div.
string of pug`);
2.2.8 pug.renderFile(path, ?options, ?callback): returns
与 pug.<font style="color:rgb(28, 30, 33);">renderFile</font>方法一样,不同的是从文件里读取内容,直接渲染并将生成的 HTML 结果返回。
- path :string
需要渲染的 Pug 代码文件的位置。 - options :object
选项对象。 - callback :function
Node.js 风格的回调函数,用于接收渲染结果。注意:这个回调是同步执行的。 - returns :string
渲染出来的 HTML 字符串。
三、基础语法
3.1 标签
- 在默认情况下,每行代码的开头就是 HTML 标签的名称,标签之间的嵌套关系使用缩进来表示。
- Pug 知道哪些元素是自闭合,并不用担心自闭合元素生成错误的代码。对于未知的标签,当然也可以主动可以通过在标签后加上
/来明确声明此标签是自闭合的。 - 对于简单元素内容,若是觉得换行与缩进过于冗余,也可以采用在标签后加上
:,:后需带上空格,以内联方式声明标签。
plain
div
li
li
li: p
div
p: span: a
html
<div>
<li></li>
<li> </li>
<li>
<p></p>
</li>
</div>
<div>
<p><span><a></a></span></p>
</div>
3.2 纯文本
- Pug 提供了四种方法来放置纯文本,纯文本内容会直接输出到 HTML 中。
- 若是识别到
<i></i>这类带有代码块的声明的内容,将会原模原样输出到 HTML 中。 - 控制输出到 HTML 中的空格,可能是学习 Pug 的过程最需要注意地方,Pug 会保留以下几种情况下的纯文本空格:
- 一行文本之中所有中间的空格。
- 在块的缩进后的开头的空格。
- 纯文本块、或者连续的管道文本行之间的换行。
- 一行末尾的空格。
- 对于管道符而言,一个
|就相当于在编译的 HTML 里实际输出一个换行符,管道后的内容将会以纯文本形式输出。 - 使用
#[Pug代码]语法,可实现类似于 JavaScript 的模板字符串语法,又或者说是字符串格式化语法。
plain
div
//- 方式一,以空格为间隔直接在标签后书写纯文本
p DeepSeek开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。
//- 方式二,以管道文本书写换行效果的纯文本
p 就拿#[strong DeepSeek-R1]来说,它的特色在于成本极低,也正是这一点戳到了OpenAI和Claude的痛处。
| 做搜索出身的百度,将积累下来的技术经验用到了模型产品当中,把RAG能力做成了模型特色,让文心一言成为了RAG领域的最强选手。
| 在文字之外,语音是一种更加自然的对话方式,在这方面,字节的豆包就有强大的端到端对话,能够处理复杂的中文内容,甚至感知人类情绪,总之是一点不输给OpenAI的《Her》。/
//- 方式三,声明纯文本块
p.
#[strong DeepSeek]开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。
该公司据报积极地从中国顶尖高校吸引年轻的人工智能研究者并招募计算机科学领域外的人以丰富其模型的认知和能力。
//- 方式四,书写原生HTML代码实现纯文本(额外多出两个"|"是为了在输出的HTML里换行,实际使用可去除)
|
|
<p>DeepSeek开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。</p>
html
<div>
<p>DeepSeek开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。</p>
<p>就拿<strong>DeepSeek-R1</strong>来说,它的特色在于成本极低,也正是这一点戳到了OpenAI和Claude的痛处。</p>做搜索出身的百度,将积累下来的技术经验用到了模型产品当中,把RAG能力做成了模型特色,让文心一言成为了RAG领域的最强选手。
在文字之外,语音是一种更加自然的对话方式,在这方面,字节的豆包就有强大的端到端对话,能够处理复杂的中文内容,甚至感知人类情绪,总之是一点不输给OpenAI的《Her》。/
<p><strong> DeepSeek</strong>开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。
该公司据报积极地从中国顶尖高校吸引年轻的人工智能研究者并招募计算机科学领域外的人以丰富其模型的认知和能力。
</p>
<p>DeepSeek开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。</p>
</div>
3.3 属性
Pug 标签属性写法有很多种,同一种属性不同的写法会导致 HTML 有不同的结果,在学习 Pug 语法时,如何书写好标签属性,是一大要点。
- ID属性与类属性,可以字面量快速生成。与 CSS 选择器写法类似,紧贴标签名称,以
#或.分割,在后面书写属性值,若是省略掉标签名称,则默认使用div作为标签。 - 布尔值属性是经过特殊处理的,当没有指定属性值的时候,这个属性值将当作布尔值处理,默认是
true。如果想要将布尔值在 HTML 表现为字符串形式,则需要额外转义。 - 利用 Pug 支持嵌入 JavaScript 代码的特点,样式类可以实现知名 Classnames 包相似的语法,同时与Web前端框架的功能有一定重复性。Classnames 语法详情可参考:https://github.com/JedWatson/classnames。
- 若多个标签元素拥有相同的属性列表,那么可以使用
&attributes语法,此语法可以将一个对象转化为一个元素的属性列表,从而批量设置标签属性。 - 对于
<>这一类特殊字符,Pug 在编译的时候会将其转换为 HTML 特殊符号编码,HTML 具体有哪些特殊字符,可以自行上网查询,如果不想将这些字符进行转义,则需要需要使用!=而不是=。
plain
// 对于属性正常普遍写法👇
.content(name="content" title="content" style="color: #333" ) 内容
.content(name="content",title="content",style="color: #333" ) 内容
//- 支持换行的形式书写书写
.content(
name="content"
title="content"
style="color: #333"
) 内容
// 字面量属性👇
header.foo__hd
main.foo__bd
section#learning-pug
footer.foo_ft
// Pug 对布尔属性的不同处理👇
div
input(type='checkbox' checked)
div
input(type='checkbox' checked=true)
//- 在为false的情况下,HTML 里的表现是去除此属性
div
input(type='checkbox' checked=false)
//- 以下两种行为都会在 HTML 里表现为字符串
div
input(type='checkbox' checked=true.toString())
div
input(type='checkbox' checked="true")
// 利用 Pug 支持嵌入 JavaScript 代码的特点👇
//- 书写JavaScript代码,需要在开头以 - 声明
- const classArr = ["a", "b", "c"];
- const classStr = "a b c";
//- 数组类之间,将会进行合并行为
div(class=classArr class=["d"])
//- 利用嵌入语法,拼接字符串类型变量
div(class=classStr + " d")
//- 支持多重嵌套,对于对象值判断value是否为true从而根据key作为类名
div(class=["deep-item", {active: true}])
// 为下列元素批量赋相同属性值👇
- const commonAttr = {style: {color: "#333"}, oneline: true, class: ["a", "b", "c"]};
.foo__item&attributes(commonAttr)
.foo__item&attributes(commonAttr)
.foo__item&attributes(commonAttr)
.foo__item&attributes(commonAttr)
.foo__item&attributes(commonAttr)
// 防转义字符处理👇
div(escaped="<code>")
div(unescaped!="<code>")
html
<!-- 对于属性正常普遍写法👇-->
<div class="content" name="content" title="content" style="color: #333">内容</div>
<div class="content" name="content" title="content" style="color: #333">内容</div>
<div class="content" name="content" title="content" style="color: #333">内容</div>
<!-- 字面量属性👇-->
<header class="foo__hd"></header>
<main class="foo__bd">
<section id="learning-pug"></section>
</main>
<footer class="foo_ft"></footer>
<!-- Pug 对布尔属性的不同处理👇-->
<div>
<input type="checkbox" checked="checked"/>
</div>
<div>
<input type="checkbox" checked="checked"/>
</div>
<div>
<input type="checkbox"/>
</div>
<div>
<input type="checkbox" checked="true"/>
</div>
<div>
<input type="checkbox" checked="true"/>
</div>
<!-- 利用 Pug 支持嵌入 JavaScript 代码的特点👇-->
<div class="a b c d"></div>
<div class="a b c d"> </div>
<div class="deep-item active"></div>
<!-- 为下列元素批量赋相同属性值👇-->
<div class="foo__item a b c" style="color:#333;" oneline="oneline"></div>
<div class="foo__item a b c" style="color:#333;" oneline="oneline"></div>
<div class="foo__item a b c" style="color:#333;" oneline="oneline"></div>
<div class="foo__item a b c" style="color:#333;" oneline="oneline"></div>
<div class="foo__item a b c" style="color:#333;" oneline="oneline"></div>
<!-- 防转义字符处理👇-->
<div escaped="<code>"></div>
<div unescaped="<code>"></div>
3.4 注释
与 Sass、less 类似,注释按是否输出到 HTML 分为两种。
plain
// 这行将会出现在HTML里
//- 这行不会出现在HTML里
//
根据换行缩进,可实现多行注释
此注释将会出现在HTML里
//-
根据换行缩进,可实现多行注释
此注释将会出现在HTML里
html
<!-- 这行将会出现在HTML里-->
<!--
根据换行缩进,可实现多行注释
此注释将会出现在HTML里
-->
3.5 循环迭代
- Pug 支持的循环语法有两种,一种是
for循环,另外一种是while循环,其中for循环可以写作each的别名。 - Pug 的循环语法是实现快速开发的一大利器,很大程度上解决在编写 HTML 代码时,对于类似于表单这一类元素,编写重复度过高还不得不复制粘贴代码的问题,短表单还好,但字段数量一多起来,维护和编写也是一件头疼事。
plain
// 使用 for/each 循环快速实现段落换行👇
//- 对于多行代码,必须在开头以-单独一行,先声明块代码,否则将会报错
-
const deepSeek = [
"DeepSeek R1是一款基于先进算法的人工智能(AI)模型,专注于自然语言处理和数据分析。 它能够理解和生成人类语言,并从大量数据中提取有价值的信息,帮助用户高效完成任务。",
"其应用场景广泛,包括但不限于智能问答、对话交流、内容创作和数据分析等。 DeepSeekR1与ChatGPT类似,都基于深度学习和自然语言处理技术,能够实现流畅的人机交互和智能化的信息处理。",
"然而,DeepSeek的成功不仅在于其技术突破,更在于其极具竞争力的成本优势。 据悉,DeepSeek仅花费了557万美元就完成了模型训练,成本仅为OpenAI旗下GPT-4的约5%。"
];
div
for val, index in deepSeek
p!= index + 1 + ". " + val
div
each val, index in deepSeek
p!= index + 1 + ". " + val
// 根据配置项快速生成表单结构👇
-
const formOpts = [
{name: "key1", label: "名称", type: "text", required: true},
{name: "key2", label: "手机号", type: "number", required: true},
{name: "key3", label: "密码", type: "number", required: true},
{name: "key4", label: "密码", type: "password", required: true},
{name: "key5", label: "确认密码", type: "password", required: true},
{name: "key6", label: "是否同意注册协议《xxx》", type: "checkbox", }
]
.demo-form
for item in formOpts
.demo-form__item(name=item.name class={"demo-form__item--required": item.required})
.demo-form__item__label
span= item.label
.demo-form__item__value
input(type=item.type)
// 简易的while循环示例👇
- let n = 0;
ul
while n < 4
li= n++
html
<!-- 使用 for/each 循环快速实现段落换行👇-->
<div>
<p>1. DeepSeek R1是一款基于先进算法的人工智能(AI)模型,专注于自然语言处理和数据分析。 它能够理解和生成人类语言,并从大量数据中提取有价值的信息,帮助用户高效完成任务。</p>
<p>2. 其应用场景广泛,包括但不限于智能问答、对话交流、内容创作和数据分析等。 DeepSeekR1与ChatGPT类似,都基于深度学习和自然语言处理技术,能够实现流畅的人机交互和智能化的信息处理。</p>
<p>3. 然而,DeepSeek的成功不仅在于其技术突破,更在于其极具竞争力的成本优势。 据悉,DeepSeek仅花费了557万美元就完成了模型训练,成本仅为OpenAI旗下GPT-4的约5%。</p>
</div>
<div>
<p>1. DeepSeek R1是一款基于先进算法的人工智能(AI)模型,专注于自然语言处理和数据分析。 它能够理解和生成人类语言,并从大量数据中提取有价值的信息,帮助用户高效完成任务。</p>
<p>2. 其应用场景广泛,包括但不限于智能问答、对话交流、内容创作和数据分析等。 DeepSeekR1与ChatGPT类似,都基于深度学习和自然语言处理技术,能够实现流畅的人机交互和智能化的信息处理。</p>
<p>3. 然而,DeepSeek的成功不仅在于其技术突破,更在于其极具竞争力的成本优势。 据悉,DeepSeek仅花费了557万美元就完成了模型训练,成本仅为OpenAI旗下GPT-4的约5%。</p>
</div>
<!-- 根据配置项快速生成表单结构👇-->
<div class="demo-form">
<div class="demo-form__item demo-form__item--required" name="key1">
<div class="demo-form__item__label"><span>名称</span></div>
<div class="demo-form__item__value">
<input type="text"/>
</div>
</div>
<div class="demo-form__item demo-form__item--required" name="key2">
<div class="demo-form__item__label"><span>手机号</span></div>
<div class="demo-form__item__value">
<input type="number"/>
</div>
</div>
<div class="demo-form__item demo-form__item--required" name="key3">
<div class="demo-form__item__label"><span>密码</span></div>
<div class="demo-form__item__value">
<input type="number"/>
</div>
</div>
<div class="demo-form__item demo-form__item--required" name="key4">
<div class="demo-form__item__label"><span>密码</span></div>
<div class="demo-form__item__value">
<input type="password"/>
</div>
</div>
<div class="demo-form__item demo-form__item--required" name="key5">
<div class="demo-form__item__label"><span>确认密码</span></div>
<div class="demo-form__item__value">
<input type="password"/>
</div>
</div>
<div class="demo-form__item" name="key6">
<div class="demo-form__item__label"><span>是否同意注册协议《xxx》</span></div>
<div class="demo-form__item__value">
<input type="checkbox"/>
</div>
</div>
</div>
<!-- 简易的while循环示例👇-->
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
3.6 条件分支
Pug 的条件分支语法有两种,这也是大多数语言里常见 if else 与 switch cass 语句。
plain
// 传统if else语法示例👇
- const status = 1;
#condition
if status === 1
p 状态开启
else if status === 0
p 其他状态
else
p 状态关闭
// switch case语法示例👇
- const count = 1;
#switch
case count
when 1
p 数量为1
when 2
p 数量为2
default
p 数量为其他
// 根据配置项快速生成表单结构,根据分支条件升级优化👇
-
const formOpts = [
{name: "key1", label: "名称", type: "text", required: true},
{name: "key2", label: "手机号", type: "number", required: true},
{name: "key3", label: "密码", type: "number", required: true},
{name: "key4", label: "密码", type: "password", required: true},
{name: "key5", label: "确认密码", type: "password", required: true},
{name: "key6", label: "是否同意注册协议《xxx》", type: "checkbox", labelPosition: "right" },
{type: "btn", confirmBtnText: "提交", cancelBtnText: "重置"},
{type: "btn"}
]
.demo-form
for item in formOpts
.demo-form__item(
name=item.name
class={"demo-form__item--required": item.required, "demo-form__item--reversal": labelPosition === "right"}
)
case item.type
when "btn"
.demo-form__item__value
button(class=["demo-form__btn", "demo-form__btn--confirm"])= item.confirmBtnText || "确定"
button.demo-form__btn= item.cancelBtnText || "取消"
default
if unLable !== false
.demo-form__item__label
span= item.label
.demo-form__item__value
input(type=item.type)
html
<!-- 传统if else语法示例👇-->
<div id="condition">
<p>状态开启</p>
</div>
<!-- switch case语法示例👇-->
<div id="switch">
<p>数量为1</p>
</div>
<!-- 根据配置项快速生成表单结构,根据分支条件升级优化👇-->
<div class="demo-form">
<div class="demo-form__item demo-form__item--required" name="key1">
<div class="demo-form__item__label"><span>名称</span></div>
<div class="demo-form__item__value">
<input type="text"/>
</div>
</div>
<div class="demo-form__item demo-form__item--required" name="key2">
<div class="demo-form__item__label"><span>手机号</span></div>
<div class="demo-form__item__value">
<input type="number"/>
</div>
</div>
<div class="demo-form__item demo-form__item--required" name="key3">
<div class="demo-form__item__label"><span>密码</span></div>
<div class="demo-form__item__value">
<input type="number"/>
</div>
</div>
<div class="demo-form__item demo-form__item--required" name="key4">
<div class="demo-form__item__label"><span>密码</span></div>
<div class="demo-form__item__value">
<input type="password"/>
</div>
</div>
<div class="demo-form__item demo-form__item--required" name="key5">
<div class="demo-form__item__label"><span>确认密码</span></div>
<div class="demo-form__item__value">
<input type="password"/>
</div>
</div>
<div class="demo-form__item" name="key6">
<div class="demo-form__item__label"><span>是否同意注册协议《xxx》</span></div>
<div class="demo-form__item__value">
<input type="checkbox"/>
</div>
</div>
<div class="demo-form__item">
<div class="demo-form__item__value">
<button class="demo-form__btn demo-form__btn--confirm">提交</button>
<button class="demo-form__btn">重置</button>
</div>
</div>
<div class="demo-form__item">
<div class="demo-form__item__value">
<button class="demo-form__btn demo-form__btn--confirm">确定</button>
<button class="demo-form__btn">取消</button>
</div>
</div>
</div>
3.7 代码嵌入
- 在上述的代码示例里,或多或少有使用
#[Pug代码]语法,这类代码就是 Pug 的嵌入语法,使用该语法能够在纯文本中更加轻松的引入定义的变量,又或则是书写新的 Pug 代码内容。 - 嵌入语法有三种,分别是:
标签= JavaScript代码、#[Pug代码]、![Pug代码],其中![Pug代码]语法将不会对<>这一类特殊字符进行转义。 - 值得一提的是,除了在 Mixin 混入里的变量,同一个文件内不管是多少级标签内声明的变量,都属于全局变量,若是重复声明相同变量名则会报错。
plain
article
- const text1 = "DeepSeek R1是一款基于先进算法的人工智能(AI)模型";
//- 引用JavaScript变量
p= text1
p= "简介:" + text1
//- 注意不可书写Pug代码,这会报错
//- p= em "DeepSeek R1是一款基于先进算法的人工智能(AI)模型"
article
- const text2 = "<strong>DeepSeek R1是一款基于先进算法的人工智能(AI)模型</strong>";
//- #{} 将会造成特殊字符转义
p #{text2}
p !{text2}
html
<article>
<p>DeepSeek R1是一款基于先进算法的人工智能(AI)模型</p>
<p>简介:DeepSeek R1是一款基于先进算法的人工智能(AI)模型</p>
</article>
<article>
<p><strong>DeepSeek R1是一款基于先进算法的人工智能(AI)模型</strong></p>
<p><strong>DeepSeek R1是一款基于先进算法的人工智能(AI)模型</strong></p>
</article>
四、进阶语法
4.1 包含注入
- 如果引入的是一个绝对路径,那么路径前面会拼接
options.basedir选项属性来进行解析,否则,路径相对于正在被编译的当前文件。 - 如果引入的不是 Pug 文件,那么就只会当作文本内容来引入,这包括 JS、CSS 文件。
bar.pug
plain
doctype HTML
HTML(lang="zh-CN")
include ./common/header.pug
body
section#my-blogs
h1.title 我的文章
div.text-content
p
include ./text/content.txt
include ./common/footer.pug
//- 引入的JS文件,将会当作文本内容来引入
script(type="text/javascript")
include ./js/bar.js
header.pug
plain
meta(charset="UTF-8")
meta(
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
)
meta(http-equiv="X-UA-Compatible" content="ie=edge")
title Document
link(rel="stylesheet" type="text/css" href="./css/common.css")
script(type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js")
footer.pug
plain
footer.footer
p 这里是页尾
script(type="text/javascript" src="./js/common.js")
content.txt
plain
DeepSeek开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。
该公司据报积极地从中国顶尖高校吸引年轻的人工智能研究者并招募计算机科学领域外的人以丰富其模型的认知和能力。
输出结果
html
<!DOCTYPE HTML>
<HTML lang="zh-CN">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="./css/common.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<body>
<section id="my-blogs">
<h1 class="title">我的文章</h1>
<div class="text-content">
<p>DeepSeek开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。
该公司据报积极地从中国顶尖高校吸引年轻的人工智能研究者并招募计算机科学领域外的人以丰富其模型的认知和能力。
</p>
</div>
</section>
<footer class="footer">
<p>这里是页尾</p>
</footer>
<script type="text/javascript" src="./js/common.js"></script>
<script type="text/javascript"></script>
</body>
</HTML>
4.2 Mixin混入
- Pug 的 Mixin 混入,实际上和函数语法差不多,又与 Sass、Less 里的
@mixin用法一样。Mixin 混入支持两种形式的参数传入,分别是传统的函数属性以及混入的标签属性。 - Minin 混入支持类似于前端框架插槽语法,可以把一整个代码块像内容一样传递进来。
基本语法示例
plain
//- 客服浮块
mixin kf-float
div(id="kf-float" class="kf-float")
.kf-float__inner
img.kf-float__img(src="kf.png")
span 联系客服
//- 板块内容结构
mixin my-plate(title, subtitle, ...other)
.my-plate
.my-plate__hd
if title
p
span.my-plate__title= title
if title
span.my-plate__subtitle= subtitle
//- 将标签属性植入内容体容器
.my-plate__bd&attributes(attributes)
//- 混入块能把内容传递进来
if block
block
.my-plate__ft
if other.length > 0
for item in other
div= item
article
+kf-float
+my-plate("标题", "副标题", "描述一", "描述二")(style="padding: 20px")
div
p 内容一
p 内容二
html
<article>
<div class="kf-float" id="kf-float">
<div class="kf-float__inner"><img class="kf-float__img" src="kf.png"/><span>联系客服</span></div>
</div>
<div class="my-plate">
<div class="my-plate__hd">
<p><span class="my-plate__title">标题</span><span class="my-plate__subtitle">副标题</span>
</p>
</div>
<div class="my-plate__bd" style="padding: 20px;"></div>
<div>
<p>内容一</p>
<p>内容二</p>
</div>
<div class="my-plate__ft">
<div>描述一</div>
<div>描述二</div>
</div>
</div>
</article>
利用 Mixin 混入功能,升级 三、基础语法 章节里用到的表单配置项代码
bash
//-
@params opts 表单配置项
@params direction 表单布局方向:row行、col列,默认以列布局
mixin generate-form(opts=[], direction="col")
.demo-form(class={"demo-form__row": direction === "row"})
.demo-form__main
for item in opts
.demo-form__item(
name=item.name
class={"demo-form__item--required": item.required, "demo-form__item--reversal": labelPosition === "right"}
)&attributes(attributes)
case item.type
when "btn"
.demo-form__item__value
button(class=["demo-form__btn", "demo-form__btn--confirm"])= item.confirmBtnText || "确定"
button.demo-form__btn= item.cancelBtnText || "取消"
default
if unLable !== false
.demo-form__item__label
span= item.label
.demo-form__item__value
input(type=item.type)
if block
.demo-form__meta
block
article
+generate-form(formOpts)
4.3 模板继承
- Pug 模板继承是一个非常强大的功能,它能够将复杂的页面模板拆分成若干个小而简洁的文件,可以说只要这个项目是多页面应用,使用继承语法那么就可以省去一大部分重复操作。
block和extends关键字是实现模板的继承的主要语法,block类似于Web前端框架里的组件插槽,每个带名字的块能够将不同的代码块内容塞入到父模板的不同地方,而extends是子模块指定要继承哪个父模块。- 在子模板中,顶级元素(没有缩进的一级)只能是带名字的块,或者是混入的定义,总之就是除去会输出到 HTML 里的代码。理解这一点非常重要,因为父模板定义了整个页面的总体布局和结构,而继承的子模板只能为其特定的块添补或者替换内容。
将 _4.1 包含注入 _章节内示例的代码,改用模板继承,能够用更简洁的代码实现。
plain
doctype HTML
HTML(lang="zh-CN")
meta(charset="UTF-8")
meta(
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
)
meta(http-equiv="X-UA-Compatible" content="ie=edge")
title Document
//- 样式注入块
block css
link(rel="stylesheet" type="text/css" href="./css/common.css")
//- 脚本注入块
block script
script(type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js")
body
block content
block footer
#footer
p 这里是页尾
block scriptend
script(type="text/javascript" src="./js/common.js")
plain
extends ./layout.pug
block scriptend
script(type="text/javascript")
include ./js/bar.js
block content
section#my-blogs
h1.title 我的文章
div.text-content
p
include ./text/content.txt
plain
DeepSeek开源其生成式人工智能算法、模型和训练细节,允许其代码可被免费地使用、修改、浏览和构建使用文档。
该公司据报积极地从中国顶尖高校吸引年轻的人工智能研究者并招募计算机科学领域外的人以丰富其模型的认知和能力。
参考资料💘
- 官方手册:
- Pug中文手册:属性 Attribute | Pug 模板引擎中文文档 | Pug中文网
- Pug官方英文版手册:Getting Started -- Pug
- pug-cli github文档 GitHub - pugjs/pug-cli: Pug's CLI interface