jade中文模板引擎简明文档
Jade是变体的HTML
来看一个官网上的Jade示例。(左边为Jade,右边为对应的HTML)
doctype html html(lang="en")headtitle= pageTitle script(type='text/javascript').if (foo) {bar(1 + 5)} bodyh1 Jade - node template engine #container.colif youAreUsingJade p You are amazing elsep Get on it!p.Jade is a terse and simple templating language with a strong focus on performance and powerful features. |
Jade - node template engineYou are amazing Jade is a terse and simple |
在这里我们可以看到,相对于HTML,Jade中的元素(Element)标记(Tag)没有用“<>”包围,其属性(Attribute)是用“()”括起来的。
另外,你可能已经注意到了,Jade的元素没有相对应的“开始标记”和“结束标记”。Jade是用“缩进”来描述元素的从属关系(与Python的语法相似)。
DOCTYPE
HTML本质上是XML,在HTML文件的起始位置需定义doctype。
doctype html |
元素及属性
前面说过,在Jade中,元素是不需要用“<>”包围的,直接写元素的标记名(TagName)即可。
div | |
diva |
在以上这个示例中, a 元素没有任何内容。而在实际开发中, a 元素一般都是包含有文本内容的,现在我们来为 a 元素添加文本内容:
diva Google |
a 元素还应该有 href 属性:
diva(href="http://www.google.com") Google |
再加一个 target 属性:
diva(href="http://www.google.com", target="_blank") Google |
还可以用“=”设置元素包含的内容。“=”后可跟任何“表达式”,可以是一个字符串、一个“变量”,也可以是“函数”或“表达式”的运算结果。“=”后的内容会被转码(escaped)。
div= 'If you think you can, you can.' | If you think you can, <b>you can</b>. |
“=”后的内容是“表达式”的例子:
div= 'If you think you can' + ', you can.' | If you think you can, <b>you can</b>. |
关于“=”后跟“变量”的示例将在后面的示例中给出。
如果希望“=”后的内容不被转码呢?可在“=”前加“!”:
div!= 'If you think you can, you can.' | If you think you can, you can. |
对于布尔属性(Boolean Attribute),若将值设为false,则不会加入该属性。见下面的示例:
button(disabled=true) Click Mebutton(disabled=false) Click Me |
还可以像下面这样设置元素的 style:
div(style={color:red, padding:'10px 5px'}) Style attributes | Style attributes |
是不是觉得这种写法完全没有必要?其实不然。如果这里 style 的值不是写死的,而是一个变量呢?是不是感觉要灵活多了?
在HTML中,除了大多数有明确关闭标记的元素外,还有一些自关闭(Self close)的元素,如:、。Jade模板解析器能自动识别自关闭元素。
img(src="/imgs/face.jpg") | ![]() |
当然,你也可以明确标明这是一个自关闭元素:
img(src="/imgs/face.jpg")/ | ![]() |
纯文本
看看下面这段HTML代码,
GoogleIf you think you can, you can. |
在这段HTML代码中,div 包含了一个 a 元素与一段没有标记包围的文本。若要用Jade表述这段HTML,div 元素和 a 元素都可以用前面所述的方法实现,但剩下的那个没有标记包围的文本就不能用前面所述的方法实现了。
如果这样写:
diva(href="http://google.com") Google If you think you can, you can. |
Jade模板解析器会认为这段文本是 a 元素包含的文本中的一部分:
如果这样写:
diva(href="http://google.com") GoogleIf you think you can, you can. |
Jade模板解析器会认为这是一个
Google |
很显然,我们无法用前面所述的方法实现要求。为解决此类问题,要使用Jade的特殊字符“竖线”(|)。正确的写法是:
diva(href="http://google.com") Google| If you think you can, you can. |
“|”告诉Jade模板解析器:将后面的内容原样输出。因此,“|”后面也可以包含HTML元素。
| this is HTML element, Google | this is HTML element, Google |
需要注意的是,“|”的“作用域”只有一行,若需要按原样输出多行文本,则要用到Jade的另一个特殊字符“.”。“.”一般用在填充
如果希望在一段纯文本中插入Jade语句,则需要引入“#[]”语法:
div.My name is #[b CYF] | My name is CYF |
嵌入Javascript代码
Jade支持嵌入Javascript代码。注意,这里指的不是运行于浏览器端的Javascript,而是指运行于Server端的Javascript。
(声明:本人并不建议在Jade中滥用嵌入逻辑代码,那样会不利于代码的可维护性与复用性。在Jade中嵌入的逻辑代码应仅仅是针对视图(View)本身的)
嵌入的Javascript代码必须以“-”开头:
- var blClosed = true; |
在Jade中嵌入Javascript代码能带来很大的便利性与灵活性。下面这个示例,用 for 循环生成了三个 div 元素:
- for(var i = 0; i < 3; i++)div This is div element | This is div element This is div element This is div element |
至于多行Javascript代码,当然可以在每一行代码前加“-”,但也有更简洁的写法,即让“-”独占一行,且Javascript“缩进”书写:
-var n = 3;for(var i = 0; i < n; i++)div This is div element | This is div element This is div element This is div element |
Jade自带的逻辑语法
Jade自带有一些逻辑语法,可与Javascript语句结合使用。这类语句前面不需要有“-”。
看完下面的示例后,你或许会想:这。。。不就是Python语法么?没错,这就是Python语法!
遍历
each ... in 语法:
- var ary = ['One', 'Two', 'Three'];each item in arydiv= item | One Two Three |
注意:前面说过,“=”后可跟“变量”,上面这个示例中“div=”后的“item”就是“变量”。
each ... in 还可获得“迭代”(iterate)的“索引”(index):
- var ary = ['One', 'Two', 'Three'];each item, index in arydiv= index + ':' + item | 1:One 2:Two 3:Three |
从上面的示例可以知道,each ... in 的第二个变量即为索引。如果将 each ... in 作用于Object,则又是另一番景象,此时第二个变量为“键名”(key name):
- var obj = {'one': 1, 'two': 2, 'three': 3};each val, key in objdiv= key + ':' + val | one:1 two:2 three:3 |
while 语法:
- var n = 0;while n < 3div= n++ | 0 1 2 |
条件判断
if 语法:
- var bl0 = false, bl1 = true;if bl0div bl0 is trueelse if bl1div bl1 is trueelsediv all are false | bl1 is true |
case 语法:
- var gender = 0;case genderwhen 0div you are a girldefaultdiv you are a boy | you are a girl |
复用块(Reusable Block)
可以在Jade中定义“复用块”,以增强代码的复用性,及便于代码的维护。“复用块”用关键字“mixin”定义,用“+”调用。
mixin showNamediv CYF+showName+showName | CYF CYF |
可将“复用块”理解为“函数”(function),它可接收“参数”(param),使“复用块”更具灵活性。
mixin showName(name)div= name+showName('CYF')+showName('Cao Yongfeng') | CYF Cao Yongfeng |
“复用块”还可接收一个“块”(block)参数,即一组Jade语句,只需将这组Jade语句以“缩进”的形式写在“mixin”下面即可。
mixin showName(name)div= nameif blockblock+showName('CYF')div Welcome to my blog | CYF Welcome to my blog |
在上个示例中,在调用“通用块”时使用了 block 参数,这是“通用块”隐含的参数,指以“缩进”的方式写在“mixin”下面的内容。
“通用块”还有另一个隐含参数“attributes”,看下面这个示例:
mixin showName(name)div(title!=attributes.title)= name+showName('CYF')(title='this is your name') | CYF |
attributes的数据来自第二个“()”。
需要注意的是,这里我们在使用attributes时用的是“!=”,而不是“=”。在这里如果用“=”,表示后面的内容会被转码,如果用“!=”,表示后面的内容不会被转码。
对C#有所了解的人都知道,C#的方法(method)支持“可变数目的参数”,Jade的“通用块”也支持“可变数目的参数”(Rest Arguments),在参数名前加“...”,即表示该参数的数目是可变的。不过需要注意的是,Jade中“可变数目的参数”与C#中“可变数目的参数”的含义是有所不同的,或许将Jade中的 Rest Arguments 理解为“其它参数”更为贴切。
mixin list(id, ...items)ul(id=id)each item in itemsli= item+list('mylist', 1, 2, 3) |
|
填充数据(Interpolation)
前面的示例中已经用到了很多用“=”给元素填充数据的方法,现在介绍另一种填充数据的方法:
- var str = 'my name is CYF';div= strdiv #{str} | my name is <b>CYF</b> my name is <b>CYF</b> |
这里用到的新方法就是使用“#{}”将一个变量的数据填充进来。从上例中可以看到,使用“#{}”与使用“=”是等效的,同样对数据进行了转码。如果不希望转码,可将“#”改为“!”:
- var str = 'my name is CYF';div!= strdiv !{str} | my name is CYF my name is CYF |
从上例可以看到,使用“!{}”与使用“!=”是等效的。
既然已经有了“=”和“!=”,为何还要引入“#{}”和“!{}”呢?这是因为有些地方只能使用“#{}”和“!{}”,而不能使用“=”和“!=”,如下面这个例子:
- var name = 'CYF';div my name is #{name} | my name is CYF |
与“=”、“!=”相比,“#{}”、“!{}”更灵活、能适应更多的场景。“=”、“!=”一般用在比较“简单”的场景。
注释
Jade的注释语法与大多数语言(Javascript、Java、C#等等)一样,使用“//”作为注释的开头:
// if you think you can, you can |
如果是多行注释,则需在新行中“缩进”书写:
//if you think you can,you can |
可是。。。,这样的注释似乎给人怪怪的感觉。注释是给开发人员看的,而不是给用户看的,用户也不会对你的注释感兴趣。基于此,Jade引入了另一种注释语法“//-”,当Jade模板解析器遇到“//-”时,会忽略后面的语句:
//- if you think you can,div you can | you can |
HTML中的“条件注释”(Conditional Comments)是写给浏览器的,因此这类注释必须输出到客户端。但是在Jade中并没有“条件注释”的语法,因此在Jade中若要写此类注释,直接按HTML的语法书写即可:
继承(extends)
Jade支持继承,即一个Jade模板继承自另一个Jade模板:
//- layout.jadedoctype htmlhtmlheadtitle this is Titleblock scriptbodyblock content//- index.jadeextends layout.jade block scriptscript(type="text/javascript", src="/js/jquery.js") block contentdiv This is content |
This is content |
在上例中,layout.jade 文件是父模板,index.jade 是子模板,它继承自 layout.jade。
在父模板中,用关键字“block”定义可在子模板中替换的块,每个“block”有一个名字,在子模板中,同样用关键字“block”跟上该名字定义需在该“block”中填充的内容。
Jade支持多重继承,即子模板也可以是其它模板的父模板。
一些简写
以下左右两边的写法是等效的:
#theId | div(id="theId") |
div#theId if you think you can, you can | div(id="theId") if you think you can, you can |
.theClass | div(class="theClass") |
div.theClass if you think you can, you can | div(class="theClass") if you think you can, you can |
div&attributes({id:'theId', class:'theClass'}) | div(id="theId",) |