HTML和CSS一个>Pug HTML模板预处理器指南 超文本标记语言一个> 詹姆斯·希巴德一个>一个ddress> 2019年5月16日 分享 作为网页设计师或开发人员,我们可能都必须编写自己的HTML代码。虽然这不是最困难的任务,但它通常会让人感觉有点无聊或重复。这就是Pug HTML预处理器的用武之地。 HTML也是静态的,这意味着如果您想要显示动态数据(例如,从API中获取),您最终总是会在JavaScript中得到一堆乱七八糟的HTML刺。这对于调试和维护来说是一场噩梦。哈巴狗是一只<一个href="https://pugjs.org">模板引擎一个>用于Node和浏览器。它可以编译为HTML,并具有简化的语法,这可以提高您的工作效率,使您的代码更具可读性。Pug使得编写可重用HTML以及呈现从数据库或API提取的数据变得容易。在本指南中,我将演示如何启动和运行Pug。我们将从npm开始安装它,复习它的基本语法,然后看几个在Pug中使用JavaScript的例子。最后,我们将通过构建一个使用Pug作为模板引擎的简单Node/Express项目来探索Pug的一些更高级的特性。 哈巴狗的用途是什么? 在我们开始研究Pug之前,让我们花点时间来理解所涉及的概念。模板引擎是负责将模板(可以使用多种语言中的任意一种编写)编译成HTML的程序。模板引擎通常会从外部源接收数据,并将这些数据注入正在编译的模板中。下面的图表说明了这一点。<!--![Processing flow for a web template system](https://upload.wikimedia.org/wikipedia/en/thumb/a/a2/TempEngWeb016.svg/245px-TempEngWeb016.svg.png) Credit: Dreftymac, [TempEngWeb016](https://en.wikipedia.org/wiki/File:TempEngWeb016.svg), [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/legalcod) --> 信贷:Dreftymac,<一个href="https://en.wikipedia.org/wiki/File:TempEngWeb016.svg">TempEngWeb016一个>,<一个href="https://creativecommons.org/licenses/by-sa/3.0/legalcod">Cc by-sa 3.0一个> 这种方法允许您重用静态网页元素,同时根据数据定义动态元素。它还有助于分离关注点,使应用程序逻辑与显示逻辑隔离。如果您的站点或web应用程序是数据驱动的,那么您更有可能从模板引擎中受益——例如用于管理员工的员工目录,列出供用户购买的各种产品的网络商店,或具有动态搜索功能的站点。如果您从API获取少量数据,则不需要模板引擎(在这种情况下,您可以使用JavaScript的本机<一个href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals">模板字符串一个>),或者如果你在做一个小型静态网站。 一点历史 同样值得注意的是,Pug曾经被称为Jade,直到2015年由于商标索赔而被迫更改名称。名称更改从2.0版开始生效。网上仍然有很多与玉石有关的资料。虽然其中一些内容可能仍然是有效的,但名称更改与主要版本碰撞同时发生的事实意味着,与之前的版本相比,Pug的语法有一些差异、弃用和删除。这些都有记录<一个href="https://github.com/pugjs/pug/issues/2305">在这里一个>.如果你有兴趣了解更多,你可以在<一个href="https://github.com/pugjs/pug/issues/2184">这个GitHub问题一个>.否则,只要确保在你与哈巴狗相关的谷歌搜索中添加“模板”这个词,就可以避免搜索结果全是狗。 安装哈巴狗 在我们开始编写一些Pug之前,我们需要安装Node、npm(与Node捆绑在一起)和<一个href="https://www.npmjs.com/package/pug-cli">pug-cli包一个>.安装Node/npm有几个选项。要么直接去<一个href="https://nodejs.org/en/download/">项目主页一个>并为您的系统下载正确的二进制文件,或使用版本管理器,例如<一个href="https://github.com/creationix/nvm">nvm一个>.我建议在可能的情况下使用版本管理器,因为这将允许您安装不同的Node版本并在它们之间随意切换。它还将消除一堆潜在的权限错误。你可以看看我们的教程。<一个href="//www.shaoxingby.com/quick-tip-multiple-versions-node-nvm/">使用nvm安装多个版本的Node.js一个>以获得更深入的指南。一旦Node和npm安装在您的系统上,您就可以安装pug-cli包装如下:npmI -g pug-cli 您可以通过键入命令来检查安装过程是否正确运行哈巴狗,版本进入终端。这将输出Pug的版本和您已经安装的CLI的版本。在撰写本报告时,情况如下:$ pug—version pug版本:2.0.3 pug-cli版本:1.0.0-alpha6 在编辑器中突出显示语法 如果您的编辑器没有为Pug提供语法高亮显示,那么寻找一个扩展来添加此功能将是一个好主意。我目前使用崇高的文本3和,开箱即用,这是什么.pug文件如下所示: 为了解决这个问题,可以安装<一个href="https://packagecontrol.io/packages/Pug">Sublime Pug包一个>: 语法高亮显示将使处理Pug文件变得更加容易,特别是那些任意长度的文件。尝试Pug HTML不安装 如果您想学习本教程中的简单示例,也可以在各种在线代码游乐场中运行它们。<一个href="https://codepen.io">CodePen一个>例如,有哈巴狗支持烘焙的权利。只需创建一个新笔,然后选择设置>超文本标记语言并选择Pug作为预处理器。这将允许您在HTML窗格中输入Pug代码,并实时查看结果。作为额外的奖励,您可以单击HTML窗格中的向下箭头并进行选择查看编译后的HTML查看Pug生成的标记。 Pug HTML的基本语法 现在我们已经安装了帕格,让我们试一试。创建一个名为pug-examples换上它。然后再创建一个名为超文本标记语言还有一个文件叫做index.pug:mkdir- p pug-examples / htmlcdpug-examples触摸index.pug 注意:触摸命令是Linux/macOS特有的。Windows用户会这么做的回声。>index.pug为了达到同样的目的。 工作的方式是我们把Pug代码写进去index.pug并且有pug-cli注意这个文件的变化。当它检测到任何时,它将获取的内容index.pug并将其渲染为HTML格式超文本标记语言目录中。要启动此操作,请在pug-examples目录,然后输入:狮子- w.-o ./html -P 您应该会看到如下内容:看指数。pug rendered /home/jim/Desktop/pug-examples/html/index.html 注意:在上述命令中,- w选项代表观看,圆点告诉帕格观看当前目录下的所有内容,- o / html。告诉Pug输出它的HTML超文本标记语言目录和- p选项修饰输出。 现在让我们根据上面的截图(抱怨语法高亮显示不足的那个截图)创建页面。输入以下内容index.pug:doctype html超文本标记语言(朗=“en”)头标题你好,世界!身体h1你好,世界!div.remarkp扁平的石头! 保存pug.index然后检查内容/ html / index . html.您应该会看到以下内容:<!文档类型超文本标记语言><超文本标记语言朗="在"><头><标题>你好,世界!标题>头><身体><h1>你好,世界!h1><div类="备注"><p>扁平的石头! !p>div>身体>超文本标记语言> 不错,是吧?Pug CLI获取了我们的Pug文件,并将其呈现为常规HTML。这个例子突出了关于《Pug》的几个要点。首先,它空白敏感,这意味着Pug使用缩进来确定哪些标记嵌套在彼此内部。例如:div.remarkp扁平的石头! ! 上面的代码产生如下结果:<div类="备注"><p>扁平的石头! !p>div> 现在看看这段代码:div.remarkp扁平的石头! ! 这会产生以下结果:<div类="备注">div><p>扁平的石头! !p> 使用什么缩进级别并不重要(如果必要,甚至可以使用制表符),但强烈建议保持缩进级别一致。在本文中,我将使用两个空格。其次,帕格没有任何结束标签.这显然会为您节省一些按键,并为Pug提供一个干净且易于阅读的语法。现在我们已经掌握了一些基本的Pug,让我们快速浏览一下它的语法。如果这些内容让你感到困惑,或者你想更深入地了解,一定要咨询<一个href="https://pugjs.org/api/getting-started.html">项目的优秀文档一个>.文档类型 可以使用Pug生成许多文档类型声明。例如doctype html将编译为<!DOCTYPE html >标准的HTML5文档类型,而doctype严格会给我们<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict// zh " "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">.Pug将尽力确保其输出对文档类型有效。标签 如前所述,Pug没有任何结束标记,并依赖于缩进进行嵌套。这可能需要一点时间来适应,但一旦你习惯了,它就会生成干净易读的代码。举个例子:导航navbar-defaultdivh1我的网站!ul李一个首页李一个第1页李一个第二页输入 上面的代码编译成这样:<导航><div><h1>我的网站!h1>div><ul><李><一个>首页一个>李><李><一个>第1页一个>李><李><一个>第二页一个>李>ul><输入/>导航> 注意,Pug非常聪明,可以关闭任何自关闭标记(例如<输入/ >元素)。类,id和属性 类和id使用.className而且# IDname符号。例如:导航# navbar-defaultdiv.container-fluidh1.navbar-header我的网站! 帕格还为我们提供了一条便捷的捷径。如果未指定标记,则假定为< div >元素:导航# navbar-default.container-fluidh1.navbar-header我的网站! 它们都编译为:<导航id="navbar-default"><div类="container-fluid"><h1类="navbar-header">我的网站!h1>div>导航> 使用括号添加属性:ul李一个(href=' / ')首页李一个(href=/第一页的)第1页李一个(href=/第二页的)第二页输入.search(类型=“文本”的名字=“搜索”占位符=“输入搜索词……”) 结果如下:<ul><李><一个href="/">首页一个>李><李><一个href="/第一页">第1页一个>李><李><一个href="/第二页">第二页一个>李>ul><输入类="搜索"类型="文本"的名字="搜索"占位符="输入搜索词…"/> 关于属性还有很多可说的。例如,您可以使用JavaScript在属性中包含变量,或者为属性分配值数组。我们将在下一节中讨论如何在Pug中使用JavaScript。纯文本和文本块 Pug提供了各种方法,用于将纯文本直接添加到呈现的HTML中。我们已经看到了如何内联添加纯文本:h1.navbar-header我的网站!我们可以在这里写任何东西…… 另一种方法是用管道字符(|):p|您已登录为|user@example.com 这就得到了以下结果:<p>您以user@example.com的身份登录p> 当处理大块的文本时,你可以只加一个点.在标签名之后,或者右括号之后,如果标签有属性:p.神圣的神圣,神圣的神圣,神圣的劳动和神圣的神圣。Ut enim ad minivenim, quis nostrud practice ullamco laboris nisi Ut aliquip ex ea commodo后果。 结果是:<p>神圣的神圣,神圣的神圣,神圣的劳动和神圣的神圣。Ut enim ad minivenim, quis nostrud practice ullamco laboris nisi Ut aliquip ex ea commodo后果。p> 评论 最后,注释可以像这样添加://我的导航栏导航# navbar-default 这个注释将被添加到渲染的HTML中:<!--My wonderful navbar--><导航id="navbar-default">导航> 你可以这样开始评论://-我美妙的导航栏导航# navbar-default 当您这样做时,注释将保留在Pug文件中,但不会出现在HTML中。注释必须出现在它们自己的行上。在这里,注释将被视为纯文本:导航# navbar-default//我的导航栏 多行注释也是可能的://我的导航栏真是太棒了!导航# navbar-default 基本语法演示 下面你可以看到一个bootstrap风格的布局演示,演示了我们迄今为止讨论过的技术:看钢笔<一个href="https://codepen.io/SitePoint/pen/wOgKPr/">哈巴狗基本演示一个>由Si必威西盟体育网页登录tePoint (<一个href="https://codepen.io/SitePoint">@必威西盟体育网页登录SitePoint一个>)在<一个href="https://codepen.io">CodePen一个>. 在Pug HTML模板中使用JavaScript Pug的一大优点是能够在模板中运行JavaScript。这使得在模板中插入变量、遍历数组和对象、有条件地呈现HTML等等变得很容易。缓冲与非缓冲代码 这是在Pug中使用JavaScript之前需要注意的一个重要区别。无缓冲的代码以负号开头(-).它不会直接向输出中添加任何东西,但它的值可以在Pug内部使用:-常量的名字=“吉姆”//-现在我可以在我的Pug代码中引用一个'name'变量 缓冲代码,另一方面,以等号(=).它计算一个JavaScript表达式并输出结果。p=“2的10次方是:”+2**10 上面的代码编译成这样:<p>2的10次方是1024p> 出于安全考虑,缓冲代码是HTML转义。p=' <脚本>警报(“嗨”)> < /脚本的 上面的代码编译成这样:<p>& lt;脚本比;alert (“;嗨“;)& lt;/脚本比;p>p > 插值 字符串插值是将模板中的一个或多个占位符替换为相应值的过程。正如我们刚刚看到的,缓冲输入提供了一种方法。另一个是使用# {}.在这里,Pug将计算花括号之间的任何代码,转义它,并将其呈现到模板中。-常量的名字=“吉姆”p你好#{名称} 上面的代码编译成这样:<p>嗨,吉姆。p> 由于花括号可以包含任何有效的JavaScript表达式,这就提供了一系列可能性:-常量的名字=“吉姆”-//-首字母大写pHi #{name.charAt(0).toUpperCase() + name.slice(1)} 编译为:<p>嗨,吉姆。p> 还可以在模板中使用未转义的值! {}.但如果输入来自不可信的来源,这就不是最好的主意。注意:当你想将变量中的值赋值给元素的属性时,你可以省略# {}.例如:img (alt =名字). 迭代 哈巴狗的每一个关键字可以轻松遍历数组:-常量员工=[安琪拉的,“吉姆”,“尼尔森”,“西蒙妮”]ul每一个员工在员工李=员工 结果如下:<ul><李>安琪拉李><李>吉姆李><李>尼尔森李><李>西蒙李>ul> 你也可以用它来遍历对象中的键:-常量员工= {“名”:“James”,“姓”:“Hibbard”ul每一个价值,关键在员工李=`$ {关键}:$ {价值}` 结果是:<ul><李>名字:James李><李>姓:希巴德李>ul> Pug还允许你提供一个else块,当数组或对象为空时执行:-常量员工=[]ul每一个员工在员工李=员工其他的李这家公司没有任何员工。也许可以雇佣一些人? 最后,注意您可以使用为作为一个别名每一个.条件 条件提供了一种非常方便的方式来根据JavaScript表达式的结果呈现不同的HTML:-常量员工= {firstName:“詹姆斯”,姓:希巴德,extn:‘12345’}#员工p=`$ {员工.firstName}$ {员工.姓}`p扩展:如果员工.extn=员工.extn其他的|N/A 在这个例子中,我们检查是否员工对象具有extn属性,然后输出该属性的值(如果它存在),或者输出文本“n/a”。JavaScript在哈巴狗演示 下面是我们在本节中讨论过的一些技术的演示。与之前的演示相比,这个演示更多地展示了Pug的优点,因为我们需要做的就是向我们的模型中添加更多的对象必威西盟体育网页登录sitePointEmployees数组中。看钢笔<一个href="https://codepen.io/SitePoint/pen/qvRmKJ/">JavaScript在哈巴狗演示一个>由Si必威西盟体育网页登录tePoint (<一个href="https://codepen.io/SitePoint">@必威西盟体育网页登录SitePoint一个>)在<一个href="https://codepen.io">CodePen一个>. 一个实际操作的例子 现在我们已经对Pug的语法及其工作原理有了合理的了解,让我们通过构建一个小型的<一个href="https://expressjs.com/">Express.js一个>应用程序来演示Pug的几个更高级的功能。此示例的代码可在<一个href="https://github.com/sitepoint-editors/beginners-guide-to-pug">GitHub一个>.注意:如果您以前没有用过Express,不用担心。它是一个Node.js的web框架,为构建web应用程序提供了一组健壮的功能。如果你想了解更多,请查看我们的<一个href="//www.shaoxingby.com/create-new-express-js-apps-with-express-generator/">开始与Express教程一个>. 首先,让我们创建一个新项目并安装Express:mkdirpug-expresscdpug-expressnpminit - ynpm我表达 接下来创建一个app.js在pug-express文件夹:触摸app.js 然后添加以下内容:常量表达=需要(“表达”);常量应用程序=表达();应用程序.得到(' / ',(要求的事情,res)= >{res.发送(“Hello, World !”);});应用程序.听(3000,()= >{控制台.日志(“监听端口3000……”);}); 这里我们声明了一个路由(/),它将用文本“Hello, World!”来响应GET请求。我们可以在浏览器中测试这一点,通过启动服务器节点app.js然后参观<一个href="http://localhost:3000">http://localhost:3000一个>.如果你看到这样的东西,那么事情就按照计划进行了: 添加数据 这个Express应用程序不会做任何太壮观的事情。我们将构建一个简单的员工目录,该目录从数据库中获取员工列表,并将其显示在一个表中。为此,我们需要一个数据库和一些数据。然而,对于这个小示例来说,安装和配置数据库有点繁琐,所以我将使用一个名为<一个href="https://github.com/typicode/json-server">json-server一个>.这将允许我们创建一个db.json文件,它将转换为一个REST API,我们可以执行CRUD操作。让我们来安装它:npmI -g json-server 现在创建前面提到的db.json项目根目录下的文件:触摸db.json 最后,我们需要一些JSON来填充它。我们将使用<一个href="https://randomuser.me/">随机用户发生器一个>,这是一个免费的开源API,用于生成随机用户数据。二十五个人就够了,所以去https://randomuser.me/api/?results=25然后把结果复制到db.json.最后,在第二个终端窗口中启动服务器:Json-server——查看db。json - p=3001 这将导致json-server在端口3001上启动,并监视数据库文件的更改。将Pug设置为模板引擎 Express对使用Pug提供了出色的支持,因此只需要进行很少的配置。首先,让我们添加Pug到我们的项目:npm我哈巴狗 然后在app.js我们需要告诉Express使用Pug:应用程序.集(“视图引擎”,“哈巴狗”); 接下来,创建一个的观点目录,然后在的观点目录,添加index.pug文件:mkdir的观点触摸视图/ index.pug 向该文件添加一些内容:doctype html超文本标记语言(朗=“en”)头标题你好,世界!身体h1你好,世界! 然后改变app.js像这样:常量表达=需要(“表达”);常量应用程序=表达();应用程序.集(“视图引擎”,“哈巴狗”);应用程序.得到(' / ',(要求的事情,res)= >{res.渲染(“指数”);});应用程序.听(3000,()= >{控制台.日志(“监听端口3000……”);}); 最后,重新启动Node服务器,然后刷新浏览器,你应该会看到: 就是这样。你可以出发了。构建员工目录 列表中的下一个任务是将一些数据交给Pug模板来显示。为此,我们需要一个从json服务器获取数据的方法。不幸的是,获取API没有在Node中实现,所以让我们使用<一个href="https://github.com/axios/axios">axios一个>,而不是流行的HTTP客户端:npm我axios 然后改变app.js像这样:常量表达=需要(“表达”);常量axios=需要(“axios”);常量应用程序=表达();应用程序.集(“视图引擎”,“哈巴狗”);应用程序.得到(' / ',异步(要求的事情,res)= >{常量查询=等待axios.得到(“http://localhost: 3001 /结果”);res.渲染(“指数”,{员工:查询.数据});});应用程序.听(3000,()= >{控制台.日志(“监听端口3000……”);}); 这里发生了几件事。我们已经把路由处理程序变成了<一个href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">异步函数一个>,这样我们就可以等待员工数据从json服务器返回,然后再将其交给模板。然后我们像以前一样呈现索引,但这一次我们传递给它一个包含所有数据的对象文字。注意:每次更改时都必须重新启动Node服务器app.js.如果你觉得这很烦人,那就走人吧<一个href="https://www.npmjs.com/package/nodemon">nodemon一个>,它会为你做这些。 现在说说哈巴狗。改变index.pug看起来像下面这样:doctype html超文本标记语言(朗=“en”)头标题员工目录链接(rel=“样式表”href=“https://cdn.jsdelivr.net/npm/semantic-ui@2.3.3 / dist / semantic.min.css”)风格.table.ui. celledimg{显示:inline-block;}页脚{边距:35px 0 15px 0;Text-align: center}身体主要#主要h1。ui.center背景.header员工目录。ui.container表格。ui.celled.table.center背景theadtrth《阿凡达》th第一个名字th姓th电子邮件th电话th城市tbody每一个员工在员工tr道明img。ui.mini.rounded.image(src=员工.图片.缩略图)道明# {employee.name.first}道明# {employee.name.last}道明# {employee.email}道明# {employee.phone}道明# {employee.location.city}tfoottrth(colspan=“6”)页脚p©#{new Date().getFullYear()}我的公司 希望没有什么令人惊讶的事情发生。我们使用<一个href="https://www.npmjs.com/package/semantic-ui-css">semantic-ui-css一个>一些造型,以及一些我们自己的风格。然后,在表体中,我们迭代数组员工我们从这里传入app.js并将它们的详细信息输出到一个表中。在页面的底部是我们的版权声明和当前年份的页脚。如果你现在刷新页面,你会看到: 模板继承 这已经很好了,但是为了使事情圆满,我将演示如何构造我们的视图,以便随着项目的发展提供最大的灵活性。我们先来创建一个layout.pug在的观点目录:触摸视图/ layout.pug 然后添加以下内容:doctype html超文本标记语言头标题员工目录链接(rel=“样式表”href=“https://cdn.jsdelivr.net/npm/semantic-ui@2.3.3 / dist / semantic.min.css”)风格.table.ui. celledimg{显示:inline-block;}页脚{边距:35px 0 15px 0;Text-align: center}身体主要#主要h1。ui.center背景.header员工目录。ui.container块的内容块页脚页脚p©#{new Date().getFullYear()}我的公司 我们在这里所做的是创建一个布局文件,它可以被项目中的其他Pug文件扩展。当您有大量的Pug文件时,这将节省大量的代码。它的工作方式是我们定义了两个内容块(块的内容而且块页脚),子模板可以替换。在的情况下页脚块,我们还定义了一些回退内容,如果子模板没有重新定义该块,这些内容将被呈现。现在我们可以讲index.pug从布局中继承的文件:扩展layout.pug块的内容表格。ui.celled.table.center背景theadtrth《阿凡达》th第一个名字th姓th电子邮件th电话th城市tbody每一个员工在员工tr道明img。ui.mini.rounded.image(src=员工.图片.缩略图)道明# {employee.name.first}道明# {employee.name.last}道明# {employee.email}道明# {employee.phone}道明# {employee.location.city}tfoottrth(colspan=“6”) 结果与之前的结果相同,但现在的代码具有更好的结构。mixin Mixins允许您创建Pug的可重用块。我们可以使用它将表行提取到它自己的文件中。创建一个名为mixin在的观点文件夹,并在该文件夹中创建名为_tableRow.pug:mkdir视图/混合触摸视图/混合/ _tableRow.pug 类型声明mixinmixin关键字。它们被编译为函数,并可以接受参数。将以下内容添加到视图/混合/ _tableRow.pug:mixintableRow(员工)tr道明img。ui.mini.rounded.image(src=员工.图片.缩略图)道明# {employee.name.first}道明# {employee.name.last}道明# {employee.email}道明# {employee.phone}道明# {employee.location.city} 现在改变index.pug像这样:扩展layout.pug包括mixin / _tableRow块的内容表格。ui.celled.table.center背景theadtrth《阿凡达》th第一个名字th姓th电子邮件th电话th城市tbody每一个员工在员工+ tableRow(员工)tfoottrth(colspan=“6”) 如您所见,我们在文件顶部导入mixin。然后通过在其名称前加上加号来调用它,并将其传递给我们的员工对象。这对于我们的小应用程序来说有点过头了,但它展示了Pug的一个非常有用的功能,它允许我们编写可重用的代码。 结论 如果你能走到这一步,做得很好!在本教程中,我们已经介绍了很多内容。我们已经了解了如何安装Pug、它的基本语法、它的JavaScript支持以及迭代和条件呈现的结构。最后,我们构建了一个功能齐全的Express应用程序,它从远程数据源提取数据并将其提供给Pug模板。帕格还有很多事要做。我鼓励你去看看它<一个href="https://pugjs.org/api/getting-started.html">优秀的文档一个>然后开始在你的项目中使用它。你也可以在一些现代JS框架中使用它,比如React或<一个href="https://vue-loader.vuejs.org/guide/pre-processors.html">Vue一个>它甚至一直都是<一个href="https://github.com/pugjs/pug">移植到其他几种语言一个>.如果您正在寻找一个挑战,为什么不尝试扩展员工目录以添加缺少的CRUD功能呢?如果你被语法搞糊涂了,别忘了<一个href="https://html-to-pug.com/">帮助总是唾手可得一个>.<一个side class="flex space-x-4"> 分享本文 下一个 HTML表单和约束验证的完整指南一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/craig-buckler/">克雷格的盾牌一个>一个rticle> HTML5模板:适用于任何项目的基本样板一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/louis-lazaris1/">路易Lazaris一个>一个rticle> 如何用PostCSS构建自己的CSS预处理程序一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/craig-buckler/">克雷格的盾牌一个>一个rticle> 从神话开始:未来的预处理器一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/jgube/">雅各Gube一个>一个rticle> 设置HTML复选框和HTML单选按钮默认值一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/craig-buckler/">克雷格的盾牌一个>一个rticle> 从HTML模板创建你自己的WordPress主题一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/matthew-higgins/">马修·希金斯一个>一个rticle>
HTML表单和约束验证的完整指南一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/craig-buckler/">克雷格的盾牌一个>
HTML5模板:适用于任何项目的基本样板一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/louis-lazaris1/">路易Lazaris一个>
如何用PostCSS构建自己的CSS预处理程序一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/craig-buckler/">克雷格的盾牌一个>
设置HTML复选框和HTML单选按钮默认值一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/craig-buckler/">克雷格的盾牌一个>
从HTML模板创建你自己的WordPress主题一个><一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/matthew-higgins/">马修·希金斯一个>