UNPKG

29.1 kBMarkdownView Raw
1# Jade - 模板引擎
2
3Jade 是一个高性能的模板引擎,它深受 [Haml](http://haml-lang.com) 影响,它是用 JavaScript 实现的, 并且可以供 [Node](http://nodejs.org) 使用.
4
5翻译: [草依山](http://jser.me) 等
6
7## 声明
8
9从 Jade `v0.31.0` 开始放弃了对于 `<script>``<style>` 标签的平文本支持. 这个问题你可以在 `<script> <style>` 标签后加上 `.` 来解决.
10
11希望这一点能让 Jade 对新手更友好, 同时也不影响到 Jade 本身的能力或者导致过度冗长.
12
13如果你有大量的文件需要转换你可以用下 [fix-jade](https://github.com/ForbesLindesay/fix-jade) 尝试自动完成这个过程.
14
15## Test drive
16
17你可以在网上[试玩 Jade](http://naltatis.github.com/jade-syntax-docs).
18
19## README 目录
20
21- [特性](#a1)
22- [其它实现](#a2)
23- [安装](#a3)
24- [浏览器支持](#a4)
25- [公开 API](#a5)
26- [语法](#a6)
27 - [行结束标志](#a6-1)
28 - [标签](#a6-2)
29 - [标签文本](#a6-3)
30 - [注释](#a6-4)
31 - [块注释](#a6-5)
32 - [内联](#a6-6)
33 - [块展开](#a6-7)
34 - [Case](#a6-8)
35 - [属性](#a6-9)
36 - [HTML](#a6-10)
37 - [Doctypes](#a6-11)
38- [过滤器](#a7)
39- [代码](#a8)
40- [循环](#a9)
41- [条件语句](#a10)
42- [模板继承](#a11)
43- [Block append/prepend](#a12)
44- [包含](#a13)
45- [Mixins](#a14)
46- [产生输出](#a15)
47- [Makefile 的一个例子](#a16)
48- [命令行的 Jade](#a17)
49- [教程](#a18)
50- [License](#a19)
51
52<a name="a1"/>
53## 特性
54
55 - 客户端支持
56 - 代码高可读
57 - 灵活的缩进
58 - 块展开
59 - Mixins
60 - 静态包含
61 - 属性改写
62 - 安全,默认代码是转义的
63 - 运行时和编译时上下文错误报告
64 - 命令行下编译jade模板
65 - HTML5 模式 (使用 ~~`!!! 5`~~ `doctype html` 文档类型)
66 - 在内存中缓存(可选)
67 - 合并动态和静态标签类
68 - 可以通过 `filters` 修改树
69 - 模板继承
70 - 原生支持 [Express JS](http://expressjs.com)
71 - 通过 `each` 枚举对象、数组甚至是不能枚举的对象
72 - 块注释
73 - 没有前缀的标签
74 - AST Filters
75 - 过滤器
76 - `:stylus` 必须已经安装 [stylus](http://github.com/LearnBoost/stylus)
77 - `:less` 必须已经安装 [less.js](http://github.com/cloudhead/less.js)
78 - `:markdown` 必须已经安装 [markdown-js](http://github.com/evilstreak/markdown-js) 或者 [node-discount](http://github.com/visionmedia/node-discount)
79 - `:cdata`
80 - `:coffeescript` 必须已经安装[coffee-script](http://jashkenas.github.com/coffee-script/)
81 - [Emacs Mode](https://github.com/brianc/jade-mode)
82 - [Vim Syntax](https://github.com/digitaltoad/vim-jade)
83 - [TextMate Bundle](http://github.com/miksago/jade-tmbundle)
84 - [Coda/SubEtha syntax Mode](https://github.com/aaronmccall/jade.mode)
85 - [Screencasts](http://tjholowaychuk.com/post/1004255394/jade-screencast-template-engine-for-nodejs)
86 - [html2jade](https://github.com/donpark/html2jade) converter
87
88<a name="a2"/>
89## 其它实现
90
91 - [php](http://github.com/everzet/jade.php)
92 - [scala](http://scalate.fusesource.org/versions/snapshot/documentation/scaml-reference.html)
93 - [ruby](https://github.com/slim-template/slim)
94 - [python](https://github.com/SyrusAkbary/pyjade)
95 - [java](https://github.com/neuland/jade4j)
96
97<a name="a3"/>
98## 安装
99
100通过 NPM:
101
102```sh
103npm install jade
104```
105
106<a name="a4"/>
107## 浏览器支持
108
109把 Jade 编译为一个可供浏览器使用的单文件,只需要简单的执行:
110
111```sh
112$ make jade.js
113```
114
115如果你已经安装了 uglifyjs (`npm install uglify-js`),你可以执行下面的命令它会生成所有的文件。其实每一个正式版本里都帮你做了这事。
116
117```sh
118make jade.min.js
119```
120
121默认情况下,为了方便调试Jade会把模板组织成带有形如 `__.lineno = 3` 的行号的形式。
122在浏览器里使用的时候,你可以通过传递一个选项 `{ compileDebug: false }` 来去掉这个。
123下面的模板
124
125```sh
126p Hello #{name}
127```
128
129会被翻译成下面的函数:
130
131```js
132function anonymous(locals, attrs, escape, rethrow) {
133 var buf = [];
134 with (locals || {}) {
135 var interp;
136 buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>');
137 }
138 return buf.join("");
139}
140```
141
142通过使用 Jade 的 `./runtime.js`你可以在浏览器使用这些预编译的模板而不需要使用 Jade, 你只需要使用 `runtime.js` 里的工具函数, 它们会放在 `jade.attrs`, `jade.escape` 这些里。 把选项 `{ client: true }` 传递给 `jade.compile()`, Jade 会把这些帮助函数的引用放在`jade.attrs`, `jade.escape`.
143
144```js
145function anonymous(locals, attrs, escape, rethrow) {
146 var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;
147 var buf = [];
148 with (locals || {}) {
149 var interp;
150 buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>');
151 }
152 return buf.join("");
153}
154```
155
156<a name="a5"/>
157## 公开 API
158
159```javascript
160var jade = require('jade');
161
162// Compile a function
163var fn = jade.compile('string of jade', options);
164fn(locals);
165```
166
167### 选项
168
169 - `self` 使用 `self` 命名空间来持有本地变量. _(默认为 `false`)_
170 - `locals` 本地变量对象
171 - `filename` 异常发生时使用,includes 时必需
172 - `debug` 输出 token 和翻译后的函数体
173 - `compiler` 替换掉 jade 默认的编译器
174 - `compileDebug` `false`的时候调试的结构不会被输出
175 - `pretty` 为输出加上了漂亮的空格缩进 _(默认为 `false`)_
176
177<a name="a6"/>
178## 语法
179
180<a name="a6-1"/>
181### 行结束标志
182
183**CRLF****CR** 会在编译之前被转换为 **LF**
184
185<a name="a6-2"/>
186### 标签
187
188标签就是一个简单的单词:
189
190```jade
191html
192```
193
194它会被转换为 `<html></html>`
195
196标签也是可以有 id 的:
197
198```jade
199div#container
200```
201
202它会被转换为 `<div id="container"></div>`
203
204怎么加 class 呢?
205
206```jade
207div.user-details
208```
209
210转换为 `<div class="user-details"></div>`
211
212多个 class 和 id? 也是可以搞定的:
213
214 div#foo.bar.baz
215
216转换为 `<div id="foo" class="bar baz"></div>`
217
218不停的 `div div div` 很讨厌啊 , 可以这样:
219
220```jade
221#foo
222.bar
223```
224
225这个算是我们的语法糖,它已经被很好的支持了,上面的会输出:
226
227```html
228<div id="foo"></div><div class="bar"></div>
229```
230
231<a name="a6-3"/>
232### 标签文本
233
234只需要简单的把内容放在标签之后:
235
236```jade
237p wahoo!
238```
239
240它会被渲染为 `<p>wahoo!</p>`.
241
242很帅吧,但是大段的文本怎么办呢:
243
244```jade
245p
246 | foo bar baz
247 | rawr rawr
248 | super cool
249 | go jade go
250```
251
252渲染为 `<p>foo bar baz rawr.....</p>`
253
254怎么和数据结合起来? 所有类型的文本展示都可以和数据结合起来,如果我们把 `{ name: 'tj', email: 'tj@vision-media.ca' }` 传给编译函数,下面是模板上的写法:
255
256```jade
257#user #{name} &lt;#{email}&gt;
258```
259
260它会被渲染为 `<div id="user">tj &lt;tj@vision-media.ca&gt;</div>`
261
262当就是要输出 `#{}` 的时候怎么办? 转义一下!
263
264 p \#{something}
265
266它会输出 `<p>#{something}</p>`
267
268同样可以使用非转义的变量 `!{html}`, 下面的模板将直接输出一个 `<script>` 标签:
269
270```jade
271- var html = "<script></script>"
272| !{html}
273```
274
275内联标签同样可以使用文本块来包含文本:
276
277```jade
278label
279 | Username:
280 input(name='user[name]')
281```
282
283或者直接使用标签文本:
284
285```jade
286label Username:
287 input(name='user[name]')
288```
289
290_只_ 包含文本的标签,比如 `<script>`, `<style>`, 和 `<textarea>` 不需要前缀 `|` 字符, 比如:
291
292```jade
293html
294 head
295 title Example
296 script
297 if (foo) {
298 bar();
299 } else {
300 baz();
301 }
302```
303
304这里还有一种选择,可以使用 `.` 来开始一段文本块,比如:
305
306```jade
307p.
308 foo asdf
309 asdf
310 asdfasdfaf
311 asdf
312 asd.
313```
314
315会被渲染为:
316
317```jade
318<p>foo asdf
319asdf
320 asdfasdfaf
321 asdf
322asd
323.
324</p>
325```
326
327这和带一个空格的 `.` 是不一样的, 带空格的会被 Jade 的解析器忽略,当作一个普通的文字:
328
329```jade
330p .
331```
332
333渲染为:
334
335```jade
336<p>.</p>
337```
338
339需要注意的是文本块需要两次转义。比如想要输出下面的文本:
340
341```jade
342<p>foo\bar</p>
343```
344
345使用:
346
347```jade
348p.
349 foo\\bar
350```
351
352<a name="a6-4"/>
353### 注释
354
355单行注释和 JavaScript 里是一样的,通过 `//` 来开始,并且必须单独一行:
356
357```jade
358// just some paragraphs
359p foo
360p bar
361```
362
363渲染为:
364
365```html
366<!-- just some paragraphs -->
367<p>foo</p>
368<p>bar</p>
369```
370
371Jade 同样支持不输出的注释,加一个短横线就行了:
372
373```jade
374//- will not output within markup
375p foo
376p bar
377```
378
379渲染为:
380
381```html
382<p>foo</p>
383<p>bar</p>
384```
385
386<a name="a6-5"/>
387### 块注释
388
389块注释也是支持的:
390
391```jade
392body
393 //
394 #content
395 h1 Example
396```
397
398渲染为:
399
400```html
401<body>
402 <!--
403 <div id="content">
404 <h1>Example</h1>
405 </div>
406 -->
407</body>
408```
409
410Jade 同样很好的支持了条件注释:
411
412```jade
413body
414 //if IE
415 a(href='http://www.mozilla.com/en-US/firefox/') Get Firefox
416```
417
418渲染为:
419
420```html
421<body>
422 <!--[if IE]>
423 <a href="http://www.mozilla.com/en-US/firefox/">Get Firefox</a>
424 <![endif]-->
425</body>
426```
427
428<a name="a6-6"/>
429### 内联
430
431Jade 支持以自然的方式定义标签嵌套:
432
433```jade
434ul
435 li.first
436 a(href='#') foo
437 li
438 a(href='#') bar
439 li.last
440 a(href='#') baz
441```
442
443<a name="a6-7"/>
444### 块展开
445
446块展开可以帮助你在一行内创建嵌套的标签,下面的例子和上面的是一样的:
447
448```jade
449ul
450 li.first: a(href='#') foo
451 li: a(href='#') bar
452 li.last: a(href='#') baz
453```
454
455<a name="a6-8"/>
456### Case
457
458`case` 表达式按下面这样的形式写:
459
460```jade
461html
462 body
463 friends = 10
464 case friends
465 when 0
466 p you have no friends
467 when 1
468 p you have a friend
469 default
470 p you have #{friends} friends
471```
472
473块展开在这里也可以使用:
474
475```jade
476friends = 5
477
478html
479 body
480 case friends
481 when 0: p you have no friends
482 when 1: p you have a friend
483 default: p you have #{friends} friends
484```
485
486<a name="a6-9"/>
487### 属性
488
489Jade 现在支持使用 `(``)` 作为属性分隔符
490
491```jade
492a(href='/login', title='View login page') Login
493```
494
495当一个值是 `undefined` 或者 `null` 属性 _不_ 会被加上,
496所以呢,它不会编译出 'something="null"'.
497
498```jade
499div(something=null)
500```
501
502Boolean 属性也是支持的:
503
504```jade
505input(type="checkbox", checked)
506```
507
508使用代码的 Boolean 属性只有当属性为 `true` 时才会输出:
509
510```jade
511input(type="checkbox", checked=someValue)
512```
513
514多行同样也是可用的:
515
516```jade
517input(type='checkbox',
518 name='agreement',
519 checked)
520```
521
522多行的时候可以不加逗号:
523
524```jade
525input(type='checkbox'
526 name='agreement'
527 checked)
528```
529
530加点空格,格式好看一点?同样支持
531
532```jade
533input(
534 type='checkbox'
535 name='agreement'
536 checked)
537```
538
539冒号也是支持的:
540
541```jade
542rss(xmlns:atom="atom")
543```
544
545假如我有一个 `user` 对象 `{ id: 12, name: 'tobi' }`
546我们希望创建一个指向 `/user/12` 的链接 `href`, 我们可以使用普通的 JavaScript 字符串连接,如下:
547
548```jade
549a(href='/user/' + user.id)= user.name
550```
551
552或者我们使用 Jade 的修改方式, 这个我想很多使用 Ruby 或者 CoffeeScript 的人会看起来像普通的 JS..:
553
554```jade
555a(href='/user/#{user.id}')= user.name
556```
557
558`class` 属性是一个特殊的属性,你可以直接传递一个数组,比如 `bodyClasses = ['user', 'authenticated']` :
559
560```jade
561body(class=bodyClasses)
562```
563
564<a name="a6-10"/>
565### HTML
566
567内联的 HTML 是可以的,我们可以使用管道定义一段文本 :
568
569```jade
570html
571 body
572 | <h1>Title</h1>
573 | <p>foo bar baz</p>
574```
575
576或者我们可以使用 `.` 来告诉 Jade 我们需要一段文本:
577
578```jade
579html
580 body.
581 <h1>Title</h1>
582 <p>foo bar baz</p>
583```
584
585上面的两个例子都会渲染成相同的结果:
586
587```jade
588<html><body><h1>Title</h1>
589<p>foo bar baz</p>
590</body></html>
591```
592
593 这条规则适应于在 Jade 里的任何文本:
594
595```
596html
597 body
598 h1 User <em>#{name}</em>
599```
600
601<a name="a6-11"/>
602### Doctypes
603
604添加文档类型只需要简单的使用 `!!!`, 或者 `doctype` 跟上下面的可选项:
605
606```jade
607!!!
608```
609
610会渲染出 _transitional_ 文档类型, 或者:
611
612```jade
613!!! 5
614```
615
616
617
618```jade
619!!! html
620```
621
622
623
624```jade
625doctype html
626```
627
628Doctype 是大小写不敏感的, 所以下面两个是一样的:
629
630```jade
631doctype Basic
632doctype basic
633```
634
635当然也是可以直接传递一段文档类型的文本:
636
637```jade
638doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
639```
640
641渲染后:
642
643```html
644<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN">
645```
646
647会输出 _HTML5_ 文档类型. 下面的默认的文档类型,可以很简单的扩展:
648
649```javascript
650var doctypes = exports.doctypes = {
651 '5': '<!DOCTYPE html>',
652 'xml': '<?xml version="1.0" encoding="utf-8" ?>',
653 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
654 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
655 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
656 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
657 '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
658 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
659 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
660};
661```
662
663通过下面的代码可以很简单的改变默认的文档类型:
664
665```javascript
666 jade.doctypes.default = 'whatever you want';
667```
668
669<a name="a7"/>
670## 过滤器
671
672过滤器前缀 `:`, 比如 `:markdown` 会把下面块里的文本交给专门的函数进行处理。查看顶部 _特性_ 里有哪些可用的过滤器。
673
674```jade
675body
676 :markdown
677 Woah! jade _and_ markdown, very **cool**
678 we can even link to [stuff](http://google.com)
679```
680
681渲染为:
682
683```html
684<body><p>Woah! jade <em>and</em> markdown, very <strong>cool</strong> we can even link to <a href="http://google.com">stuff</a></p></body>
685```
686
687<a name="a8"/>
688## 代码
689
690Jade 目前支持三种类型的可执行代码。第一种是前缀 `-`, 这是不会被输出的:
691
692```jade
693- var foo = 'bar';
694```
695
696这可以用在条件语句或者循环中:
697
698```jade
699- for (var key in obj)
700 p= obj[key]
701```
702
703由于 Jade 的缓存技术,下面的代码也是可以的:
704
705```jade
706- if (foo)
707 ul
708 li yay
709 li foo
710 li worked
711- else
712 p oh no! didnt work
713```
714
715哈哈,甚至是很长的循环也是可以的:
716
717 - if (items.length)
718 ul
719 - items.forEach(function(item){
720 li= item
721 - })
722
723所以你想要的!
724
725下一步我们要 _转义_ 输出的代码,比如我们返回一个值,只要前缀一个 `=`
726
727```jade
728- var foo = 'bar'
729= foo
730h1= foo
731```
732
733它会渲染为 `bar<h1>bar</h1>`. 为了安全起见,使用 `=` 输出的代码默认是转义的,如果想直接输出不转义的值可以使用 `!=`
734
735```jade
736p!= aVarContainingMoreHTML
737```
738
739Jade 同样是设计师友好的,它可以使 JavaScript 更直接更富表现力。比如下面的赋值语句是相等的,同时表达式还是通常的 JavaScript:
740
741```jade
742- var foo = 'foo ' + 'bar'
743foo = 'foo ' + 'bar'
744```
745
746Jade 会把 `if`, `else if`, `else`, `until`, `while`, `unless` 同别的优先对待, 但是你得记住它们还是普通的 JavaScript:
747
748```jade
749if foo == 'bar'
750 ul
751 li yay
752 li foo
753 li worked
754else
755 p oh no! didnt work
756```
757
758<a name="a9"/>
759## 循环
760
761尽管已经支持 JavaScript 原生代码,Jade 还是支持了一些特殊的标签,它们可以让模板更加易于理解,其中之一就是 `each`, 这种形式:
762
763```jade
764each VAL[, KEY] in OBJ
765```
766
767一个遍历数组的例子 :
768
769```jade
770- var items = ["one", "two", "three"]
771each item in items
772 li= item
773```
774
775渲染为:
776
777```html
778<li>one</li>
779<li>two</li>
780<li>three</li>
781```
782
783遍历一个数组同时带上索引:
784
785```jade
786items = ["one", "two", "three"]
787each item, i in items
788 li #{item}: #{i}
789```
790
791渲染为:
792
793```html
794<li>one: 0</li>
795<li>two: 1</li>
796<li>three: 2</li>
797```
798
799遍历一个数组的键值:
800
801```jade
802obj = { foo: 'bar' }
803each val, key in obj
804 li #{key}: #{val}
805```
806
807将会渲染为:`<li>foo: bar</li>`
808
809Jade 在内部会把这些语句转换成原生的 JavaScript 语句,就像使用 `users.forEach(function(user){`, 词法作用域和嵌套会像在普通的 JavaScript 中一样:
810
811```jade
812each user in users
813 each role in user.roles
814 li= role
815```
816
817如果你喜欢,也可以使用 `for`
818
819```jade
820for user in users
821 for role in user.roles
822 li= role
823```
824
825<a name="a10"/>
826## 条件语句
827
828Jade 条件语句和使用了(`-`) 前缀的 JavaScript 语句是一致的,然后它允许你不使用圆括号,这样会看上去对设计师更友好一点,
829同时要在心里记住这个表达式渲染出的是 _常规_ JavaScript:
830
831```jade
832for user in users
833 if user.role == 'admin'
834 p #{user.name} is an admin
835 else
836 p= user.name
837```
838
839和下面的使用了常规 JavaScript 的代码是相等的:
840
841```jade
842for user in users
843 - if (user.role == 'admin')
844 p #{user.name} is an admin
845 - else
846 p= user.name
847```
848
849Jade 同时支持 `unless`, 这和 `if (!(expr))` 是等价的:
850
851```jade
852for user in users
853 unless user.isAnonymous
854 p
855 | Click to view
856 a(href='/users/' + user.id)= user.name
857```
858
859<a name="a11"/>
860## 模板继承
861
862Jade 支持通过 `block``extends` 关键字来实现模板继承。 一个块就是一个 Jade 的 block ,它将在子模板中实现,同时是支持递归的。
863
864Jade 块如果没有内容,Jade 会添加默认内容,下面的代码默认会输出 `block scripts`, `block content`, 和 `block foot`.
865
866```jade
867html
868 head
869 h1 My Site - #{title}
870 block scripts
871 script(src='/jquery.js')
872 body
873 block content
874 block foot
875 #footer
876 p some footer content
877```
878
879现在我们来继承这个布局,简单创建一个新文件,像下面那样直接使用 `extends`,给定路径(可以选择带 `.jade` 扩展名或者不带). 你可以定义一个或者更多的块来覆盖父级块内容, 注意到这里的 `foot`_没有_ 定义,所以它还会输出父级的 "some footer content"。
880
881```jade
882extends extend-layout
883
884block scripts
885 script(src='/jquery.js')
886 script(src='/pets.js')
887
888block content
889 h1= title
890 each pet in pets
891 include pet
892```
893
894同样可以在一个子块里添加块,就像下面实现的块 `content` 里又定义了两个可以被实现的块 `sidebar``primary`,或者子模板直接实现 `content`
895
896```jade
897extends regular-layout
898
899block content
900 .sidebar
901 block sidebar
902 p nothing
903 .primary
904 block primary
905 p nothing
906```
907
908<a name="a12"/>
909
910## 前置、追加代码块
911
912Jade允许你 _替换_ (默认)、 _前置__追加_ blocks. 比如,假设你希望在 _所有_ 页面的头部都加上默认的脚本,你可以这么做:
913
914
915```jade
916html
917 head
918 block head
919 script(src='/vendor/jquery.js')
920 script(src='/vendor/caustic.js')
921 body
922 block content
923```
924
925现在假设你有一个Javascript游戏的页面,你希望在默认的脚本之外添加一些游戏相关的脚本,你可以直接`append`上代码块:
926
927
928```jade
929extends layout
930
931block append head
932 script(src='/vendor/three.js')
933 script(src='/game.js')
934```
935
936使用 `block append``block prepend``block` 是可选的:
937
938```jade
939extends layout
940
941append head
942 script(src='/vendor/three.js')
943 script(src='/game.js')
944```
945
946<a name="a13"/>
947## 包含
948
949Includes 允许你静态包含一段 Jade, 或者别的存放在单个文件中的东西比如 CSS, HTML 非常常见的例子是包含头部和页脚。 假设我们有一个下面目录结构的文件夹:
950
951```
952./layout.jade
953./includes/
954 ./head.jade
955 ./tail.jade
956```
957
958下面是 `layout.jade` 的内容:
959
960```jade
961html
962 include includes/head
963 body
964 h1 My Site
965 p Welcome to my super amazing site.
966 include includes/foot
967```
968
969这两个包含 `includes/head``includes/foot` 都会读取相对于给 `layout.jade` 参数`filename` 的路径的文件, 这是一个绝对路径,不用担心Express帮你搞定这些了。Include 会解析这些文件,并且插入到已经生成的语法树中,然后渲染为你期待的内容:
970
971```html
972<html>
973 <head>
974 <title>My Site</title>
975 <script src="/javascripts/jquery.js">
976 </script><script src="/javascripts/app.js"></script>
977 </head>
978 <body>
979 <h1>My Site</h1>
980 <p>Welcome to my super lame site.</p>
981 <div id="footer">
982 <p>Copyright>(c) foobar</p>
983 </div>
984 </body>
985</html>
986```
987
988前面已经提到,`include` 可以包含比如 HTML 或者 CSS 这样的内容。给定一个扩展名后,Jade 不会把这个文件当作一个 Jade 源代码,并且会把它当作一个普通文本包含进来:
989
990```
991html
992 head
993 //- css and js have simple filters that wrap them in
994 <style> and <script> tags, respectively
995 include stylesheet.css
996 include script.js
997 body
998 //- "markdown" files will use the "markdown" filter
999 to convert Markdown to HTML
1000 include introduction.markdown
1001 //- html files have no filter and are included verbatim
1002 include content.html
1003```
1004
1005Include 也可以接受块内容,给定的块将会附加到包含文件 _最后_ 的块里。 举个例子,`head.jade` 包含下面的内容:
1006
1007```jade
1008head
1009 script(src='/jquery.js')
1010```
1011
1012我们可以像下面给`include head`添加内容, 这里是添加两个脚本.
1013
1014```
1015html
1016 include head
1017 script(src='/foo.js')
1018 script(src='/bar.js')
1019 body
1020 h1 test
1021```
1022
1023
1024在被包含的模板中,你也可以使用`yield`语句。`yield`语句允许你明确地标明`include`的代码块的放置位置。比如,假设你希望把代码块放在scripts之前,而不是附加在scripts之后:
1025
1026```jade
1027head
1028 yield
1029 script(src='/jquery.js')
1030 script(src='/jquery.ui.js')
1031```
1032
1033由于被包含的Jade会按字面解析并合并到AST中,词法范围的变量的效果和直接写在同一个文件中的相同。这就意味着`include`可以用作partial的替代,例如,假设我们有一个引用了`user`变量的user.jade`文件:
1034
1035
1036```jade
1037h1= user.name
1038p= user.occupation
1039```
1040
1041接着,当我们迭代users的时候,只需简单地加上`include user`。因为在循环中`user`变量已经被定义了,被包含的模板可以访问它。
1042
1043
1044
1045```jade
1046users = [{ name: 'Tobi', occupation: 'Ferret' }]
1047
1048each user in users
1049 .user
1050 include user
1051```
1052
1053以上代码会生成:
1054
1055```html
1056<div class="user">
1057 <h1>Tobi</h1>
1058 <p>Ferret</p>
1059</div>
1060```
1061
1062`user.jade`引用了`user`变量,如果我们希望使用一个不同的变量`user`,那么我们可以直接定义一个新变量`user = person`,如下所示:
1063
1064```jade
1065each person in users
1066 .user
1067 user = person
1068 include user
1069```
1070
1071
1072<a name="a14"/>
1073## Mixins
1074
1075Mixins 在编译的模板里会被 Jade 转换为普通的 JavaScript 函数。 Mixins 可以还参数,但不是必需的:
1076
1077```jade
1078mixin list
1079 ul
1080 li foo
1081 li bar
1082 li baz
1083```
1084
1085使用不带参数的 mixin 看上去非常简单,在一个块外:
1086
1087```jade
1088h2 Groceries
1089mixin list
1090```
1091
1092Mixins 也可以带一个或者多个参数,参数就是普通的 JavaScript 表达式,比如下面的例子:
1093
1094```jade
1095mixin pets(pets)
1096 ul.pets
1097 - each pet in pets
1098 li= pet
1099
1100mixin profile(user)
1101 .user
1102 h2= user.name
1103 mixin pets(user.pets)
1104```
1105
1106会输出像下面的 HTML:
1107
1108
1109```html
1110<div class="user">
1111 <h2>tj</h2>
1112 <ul class="pets">
1113 <li>tobi</li>
1114 <li>loki</li>
1115 <li>jane</li>
1116 <li>manny</li>
1117 </ul>
1118</div>
1119```
1120
1121<a name="a15"/>
1122## 产生输出
1123
1124假设我们有下面的 Jade 源码:
1125
1126```jade
1127- var title = 'yay'
1128h1.title #{title}
1129p Just an example
1130```
1131
1132`compileDebug` 选项不是 `false`, Jade 会编译时会把函数里加上 `__.lineno = n;`, 这个参数会在编译出错时传递给 `rethrow()`, 而这个函数会在 Jade 初始输出时给出一个有用的错误信息。
1133
1134```js
1135function anonymous(locals) {
1136 var __ = { lineno: 1, input: "- var title = 'yay'\nh1.title #{title}\np Just an example", filename: "testing/test.js" };
1137 var rethrow = jade.rethrow;
1138 try {
1139 var attrs = jade.attrs, escape = jade.escape;
1140 var buf = [];
1141 with (locals || {}) {
1142 var interp;
1143 __.lineno = 1;
1144 var title = 'yay'
1145 __.lineno = 2;
1146 buf.push('<h1');
1147 buf.push(attrs({ "class": ('title') }));
1148 buf.push('>');
1149 buf.push('' + escape((interp = title) == null ? '' : interp) + '');
1150 buf.push('</h1>');
1151 __.lineno = 3;
1152 buf.push('<p>');
1153 buf.push('Just an example');
1154 buf.push('</p>');
1155 }
1156 return buf.join("");
1157 } catch (err) {
1158 rethrow(err, __.input, __.filename, __.lineno);
1159 }
1160}
1161```
1162
1163`compileDebug` 参数是 `false`, 这个参数会被去掉,这样对于轻量级的浏览器端模板是非常有用的。结合 Jade 的参数和当前源码库里的 `./runtime.js` 文件,你可以通过 `toString()` 来编译模板而不需要在浏览器端运行整个 Jade 库,这样可以提高性能,也可以减少载入的 JavaScript 数量。
1164
1165```js
1166function anonymous(locals) {
1167 var attrs = jade.attrs, escape = jade.escape;
1168 var buf = [];
1169 with (locals || {}) {
1170 var interp;
1171 var title = 'yay'
1172 buf.push('<h1');
1173 buf.push(attrs({ "class": ('title') }));
1174 buf.push('>');
1175 buf.push('' + escape((interp = title) == null ? '' : interp) + '');
1176 buf.push('</h1>');
1177 buf.push('<p>');
1178 buf.push('Just an example');
1179 buf.push('</p>');
1180 }
1181 return buf.join("");
1182}
1183```
1184
1185<a name="a16"/>
1186## Makefile 的一个例子
1187
1188通过执行 `make`, 下面的 Makefile 例子可以把 `pages/*.jade` 编译为 `pages/*.html`
1189
1190```make
1191JADE = $(shell find pages/*.jade)
1192HTML = $(JADE:.jade=.html)
1193
1194all: $(HTML)
1195
1196%.html: %.jade
1197 jade < $< --path $< > $@
1198
1199clean:
1200 rm -f $(HTML)
1201
1202.PHONY: clean
1203```
1204
1205这个可以和 `watch(1)` 命令起来产生像下面的行为:
1206
1207```sh
1208$ watch make
1209```
1210
1211<a name="a17"/>
1212## 命令行的 Jade
1213
1214```
1215
1216使用: jade [options] [dir|file ...]
1217
1218选项:
1219
1220 -h, --help 输出帮助信息
1221 -v, --version 输出版本号
1222 -o, --out <dir> 输出编译后的 HTML 到 <dir>
1223 -O, --obj <str> JavaScript 选项
1224 -p, --path <path> 在处理 stdio 时,查找包含文件时的查找路径
1225 -P, --pretty 格式化 HTML 输出
1226 -c, --client 编译浏览器端可用的 runtime.js
1227 -D, --no-debug 关闭编译的调试选项(函数会更小)
1228 -w, --watch 监视文件改变自动刷新编译结果
1229
1230Examples:
1231
1232 # 编译整个目录
1233 $ jade templates
1234
1235 # 生成 {foo,bar}.html
1236 $ jade {foo,bar}.jade
1237
1238 # 在标准IO下使用jade
1239 $ jade < my.jade > my.html
1240
1241 # 在标准IO下使用jade, 同时指定用于查找包含的文件
1242 $ jade < my.jade -p my.jade > my.html
1243
1244 # 在标准IO下使用jade
1245 $ echo "h1 Jade!" | jade
1246
1247 # foo, bar 目录渲染到 /tmp
1248 $ jade foo bar --out /tmp
1249
1250```
1251
1252*注意: 从 `v0.31.0` 的 `-o` 选项已经指向 `--out`, `-O` 相应做了交换*
1253
1254<a name="a18"/>
1255## 教程
1256
1257 - cssdeck interactive [Jade syntax tutorial](http://cssdeck.com/labs/learning-the-jade-templating-engine-syntax)
1258 - cssdeck interactive [Jade logic tutorial](http://cssdeck.com/labs/jade-templating-tutorial-codecast-part-2)
1259 - in [Japanese](http://blog.craftgear.net/4f501e97c1347ec934000001/title/10%E5%88%86%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8Bjade%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3)
1260
1261<a name="a19"/>
1262## License
1263
1264(The MIT License)
1265
1266Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
1267
1268Permission is hereby granted, free of charge, to any person obtaining
1269a copy of this software and associated documentation files (the
1270'Software'), to deal in the Software without restriction, including
1271without limitation the rights to use, copy, modify, merge, publish,
1272distribute, sublicense, and/or sell copies of the Software, and to
1273permit persons to whom the Software is furnished to do so, subject to
1274the following conditions:
1275
1276The above copyright notice and this permission notice shall be
1277included in all copies or substantial portions of the Software.
1278
1279THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
1280EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1281MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1282IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1283CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1284TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1285SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.