Express框架里内嵌了Jade模板引擎。正好项目里也要用到,本篇整理了下Jade的相关用法。css
安装很简单:html
npm install jade –global
安装后本地随便新建一个sample.jade文件,执行:前端
jade sample.jade
就能将其翻译成标准的sample.html源文件了。执行时能够带上参数,经过jade -h查看支持的命令参数:jquery
经常使用的命令参数,好比-P(大写,命令参数是大小写敏感的)。Jade默认编译出来的html源文件里是没有缩进的,不便于开发。加上-P参数后,编译出来的html源文件里就有缩进了:npm
jade -P sample.jade
还有-w用来watch监视jade文件,每次改动保存后自动编译成html文件,省去手动执行命令的麻烦:json
jade -P -w sample.jade
-O用来给jade文件传递对象或JSON文件,用以替换模板内的变量:后端
jade -P -w sample.jade -O sample.json
传统的HTML标签写尖括号很麻烦,Jade里能够省略尖括号,直接写标签名。标签间的嵌套关系用换行加空格来实现。紧接在标签名后加上.xx或#xx,就能给标签添加css类名和id。标签名后第一个空格后面的内容会被编译成标签内的文本内容。例如:sass
doctype html html head body h1.titleClass#titleID My First Jade Page //编译出来的结果 <!DOCTYPE html> <html> <head></head> <body> <h1 id="titleID" class="titleClass">My First Jade Page</h1> </body> </html>
是否是感受写起来简单多了。由于css类名和id是最经常使用的标签属性,因此Jade简化了它俩的写法,能够紧接在标签名后面。但标签属性的正统写法应该是写入()括号内,多个属性用逗号隔开(css类名和id也能够写入()括号内):markdown
a(href='http://www.jackzxl.net', target='_blank') 个人主页 //编译出来的结果 <a href="http://www.jackzxl.net" target="_blank">个人主页</a>
HTML里最经常使用的标签就是div了,因此Jade提供了第二种简化写法,若是不写标签名默认就是div:框架
.divClass#divID 我是一个div //编译出来的结果 <div id="divID" class="divClass">我是一个div</div>
单行文本像上面这样接在标签名后的空格后面便可。多行文本有两种写法。第一种写法是在标签名后紧接一个.点。这样后面的内容会被Jade模板视做文本域而保留换行符。例如:
p. 第1行文本 第2行文本 第3行文本 第4行文本 //编译出来的结果 <p> 第1行文本 第2行文本 第3行文本 第4行文本 </p>
但因为是文本域,所以用这种写法的话,里面要嵌套标签时,只能写原生的HTML标签了:
p. 第1行文本 第2行文本 第3行文本 第4行文本 //编译出来的结果 <p> <span>第1行文本</span> 第2行文本 第3行文本 第4行文本 </p>
多行文本的第二种写法是在每行前加上|竖线符。并且若是开发者以为第一种写法里写原生HTML标签不爽,用这种写法,能够用Jade语法来嵌套标签。例如:
p span 第1行文本 | 第2行文本 | 第3行文本 | 第4行文本 //编译出来的结果 <p><span>第1行文本</span>第2行文本 第3行文本 第4行文本 <p>
多行文本的写法不只可用于p标签等,也常见于style和script标签,例如:
script. console.log("open mind"); console.log("learning quick"); console.log("work hard");
若是仅仅上面这些快速编写HTML的功能,那Jade也不必存在了。各类编辑器都有插件能够实现这种快速编写的功能,例如sublime的Emmet插件。模板引擎的真正强大之处能够实现函数式的开发。先看变量。
变量声明很简单,前面加上-横杠。使用变量只要#{变量名}就好了。例如:
- var cs = 'UTF-8' meta(charset='#{cs}') //编译出来的结果 <meta charset="UTF-8">
但注意用#{}输出的变量数据会执行HTML转码,例如:
- var alertData = '<script>alert(1);</script>' p #{alertData} //编译出来的结果 <p><script>alert(1);</script></p>
本来想被执行的script脚本,被直接做为文本打印出来了。若是不想HTML转码,能够将#改为!叹号:
- var alertData = '<script>alert(1);</script>' p !{alertData} //编译出来的结果 <p><script>alert(1);</script></p>
那若是页面就想输出#{}和!{}呢?能够前面加\反斜杠来让Jade引擎不编译变量:
p \#{alertData} p \!{alertData} //编译出来的结果 <p>#{alertData}</p> <p>!{alertData}</p>
除了用#{}和!{}外,也能够在标签后面紧接=等号(不转义用!=)来输出变量。例如:
p= alertData p!= alertData
效果和上面是同样的。这两种写法#{}和=等号输出的区别以下:
input(value='#{aaa}') input(value=aaa) //编译出来的结果 <input value="undefined"> <input>
能够看出用#{}若是变量未定义,将会编译成undefined做为初始值。但用=等号来编译变量的话,若是变量未定义就忽略。
有了变量就能轻松实现先后端分离。数据保存在JSON文件里。前端用Jade模板制做页面,在须要显示数据处用变量来实现。例如sample.json文件里:
{ "charset": "UTF-8", "title": "My First Jade Page" }
sample.jade文件里:
doctype html html head meta(charset='#{charset}') body h1.titleClass#titleID #{title}
执行命令:jade -P -w sample.jade -O sample.json
后Jade文件里的变量被自动替换。编译出来的sample.html:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <h1 id="titleID" class="titleClass">My First Jade Page</h1> </body> </html>
Jade模板支持JavaScript语句:
最多见的if-else:
- var author = 'Jack'; if author p 做者:#{author} else p 无做者 //编译出来的结果 <p>做者:Jack</p>
Jade还支持unless语句,它是if-else的反向,写法都同样,用的很少就不举例了。
Jade里的case-when语句就是JavaScript里的switch-case语句(不知为什么…):
- var authors = ['Jack', 'Bill']; case authors[0] when 'Jack' p 做者是Jack when 'Bill' p 做者是Bill default p 无做者 //编译出来的结果 <p>做者是Jack</p>
循环遍历用for-in(注意上面的if-else,case-when语句前不用像变量那样加上-横杠,但for的前面要加上-横杠。若是漏写-横杠,会被解析为标签):
- var person = {name:'Jack', gender: 'Male'} - for (var prop in person) p= person[prop] //编译出来的结果 <p>Jack</p> <p>Male</p>
循环遍历也能够用each-in(each前的-横杠加不加都可):
- var employee = {name:'Jack', gender: 'male'} - each value, key in person p #{key}: #{value} - var language = ['Java', 'JavaScript', 'C++'] ul each item in language li #{item} //编译出来的结果 <p>name: Jack</p> <p>gender: male</p> <ul> <li>Java</li> <li>JavaScript</li> <li>C++</li> </ul>
循环遍历也能够用while(一样前面加不加-横杠都可):
- var n = 0 ul while n < 4 li= n++ //编译出来的结果 <ul> <li>0</li> <li>1</li> <li>2</li> <li>3</li> </ul>
Mixin也不是个什么新的概念,例如sass里也用Mixin封装css代码,即能重用代码,并且维护简单。Jade也支持Mixin,能够理解为function,最简单的无参数的代码函数:
mixin sayHi p Hi +sayHi //编译出来的结果 <p>Hi</p>
上面声明了一个mixin无参函数sayHi,调用时函数名前加上+加号。如今给mixin加上参数:
mixin personInfo(name, hobbies) p #{name}'s hobbies: ul.hobby each hobby in hobbies li= hobby +personInfo('Jack', ['movie', 'music']) //编译出来的结果 <p>Jack's hobbies:</p> <ul class="hobby"> <li>movie</li> <li>music</li> </ul>
函数内天然也可调用其余函数,例如上面两个函数嵌套起来。这些和普通JavaScript的函数表现一致,没啥好多介绍的:
mixin personInfo(name, hobbies) +sayHi p #{name}'s hobbies: ul.hobby each hobby in hobbies li= hobby +personInfo('Jack', ['movie', 'music'])
mixin能够实现代码的复用。文件与文件间经常使用模板来实现代码复用。Jade用block和extends来实现模板的继承。block块就是定义一段HTML模块:
block scripts script(src='jquery.js') script(src='underscore.js') script(src='backbone.js') //编译出来的结果 <script src="jquery.js"></script> <script src="underscore.js"></script> <script src="backbone.js"></script>
上面的块名就是scripts。定义好的block后,本文件内能够直接用block scripts来调用,这和mixin做用差很少,都能实现代码复用。但block真正的做用在于占位,供子文件继承,能够理解为传统OO语言里的虚函数。父文件里定义的block,子文件里用extends来继承并重写。
例如每一个文件的页头都同样,就body里内容不同,能够写一个header.jade:
doctype html html head meta(charset='#{charset}') block scripts script(src='jquery.js') script(src='underscore.js') script(src='backbone.js') body block content p please write content
每一个页面的header都长这样。而body里定义了block content,这里block能够理解为一个占位符placeholder,须要继承它的文件重写block content。
根据业务需求写页面主体部分,例如sample.jade改为这样:
extends header block content h1.titleClass#titleID #{title} a(href='http://www.jackzxl.net', target='_blank') 个人主页 ……
在sample.jade里,开头用extends代表和header.jade的继承关系。而后根据业务重写header.jade里的block content。
执行jade -P -w sample.jade -O sample.json
就能看到和以前如出一辙的页面。引擎加载流程是:解析sample.jade,发现开头有extends,就去解析header.jade,将其编译成html。此时html里的body里是<p>please write content</p>
。解析完header.jade就继续解析sample.jade,发现block content,因而会将定义在header.jade里的block content替换掉。最终输出的是正确的页面内容,而不是<p>please write content</p>
。
(但若是你执行的是jade -P -w header.jade -O sample.json
会发现body里内容为<p>please write content</p>
)
除继承外还能够用include包含。Include会将内容无脑全拷贝进去。例如上面的sample.jade第一行extends header改为include header。编译出来的结果:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script src="jquery.js"></script> <script src="underscore.js"></script> <script src="backbone.js"></script> </head> <body> <p>please write content</p> </body> </html> <h1 id="titleID" class="titleClass">My First Jade Page</h1> <a href="http://www.jackzxl.net" target="_blank">个人主页</a>
能够看出与extends不一样,include就是无脑将另外一个文件里的内容直接拷贝进去,不像block + extends能够重写block。因此结果是错误的。
小细节注意:include包括extends若是省略后缀名,Jade默认该文件时.jade会进行编译。但若是另外一个文件里写的是原生的html,须要写明后缀名为.html(例如include xx.html),明确告诉Jade不要编译。
Jade里加上//就能添加注释,用双斜杠的注释会被输出到html源码里。例如:
//一行无心义的注释 //编译出来的结果 <!--一行无心义的注释-->
若是不想在html源码里输出注释,用//-,在双斜杠后加一横杠。例如:
//-一行无心义的注释,编译时直接跳过该行,不会被输出到HTML源码里
咱们知道html里还能够写注释型的条件语句,经常使用于兼容IE。Jade里你一样能够写这些条件语句,例如将上面header.jade改为能识别IE89,应用不一样的class:
doctype html <!--[if IE 8]><html class='ie8'><![endif]--> <!--[if IE 9]><html class='ie9'><![endif]--> <!--[if !IE]><!--><html><!--<![endif]--> head meta(charset='#{charset}') block scripts script(src='jquery.js') script(src='underscore.js') script(src='backbone.js') body block content p please write content </html>
上面由于有了条件语句,因此html标签用尖括号括了起来,所以最下面要手动加上来闭合标签。并且Jade是空格缩进敏感的,须要将原先的head和body包括里面内容,全往前缩进2个空格。
Jade一样兼容其余模块,例如写博客爱用的markdown,写css爱用的less,还有coffeeScript等。只要npm安装好后,用:冒号+模块名就能声明使用这些模块,例如:
:markdown ... :less ... :coffee ...
以:markdown 为例,会把下面块里的文本交给markdown去进行处理。