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