1 | # Jade - 模板引擎
|
2 |
|
3 | Jade 是一个高性能的模板引擎,它深受 [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
|
103 | npm 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
|
118 | make jade.min.js
|
119 | ```
|
120 |
|
121 | 默认情况下,为了方便调试Jade会把模板组织成带有形如 `__.lineno = 3` 的行号的形式。
|
122 | 在浏览器里使用的时候,你可以通过传递一个选项 `{ compileDebug: false }` 来去掉这个。
|
123 | 下面的模板
|
124 |
|
125 | ```sh
|
126 | p Hello #{name}
|
127 | ```
|
128 |
|
129 | 会被翻译成下面的函数:
|
130 |
|
131 | ```js
|
132 | function 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
|
145 | function 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
|
160 | var jade = require('jade');
|
161 |
|
162 | // Compile a function
|
163 | var fn = jade.compile('string of jade', options);
|
164 | fn(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
|
191 | html
|
192 | ```
|
193 |
|
194 | 它会被转换为 `<html></html>`
|
195 |
|
196 | 标签也是可以有 id 的:
|
197 |
|
198 | ```jade
|
199 | div#container
|
200 | ```
|
201 |
|
202 | 它会被转换为 `<div id="container"></div>`
|
203 |
|
204 | 怎么加 class 呢?
|
205 |
|
206 | ```jade
|
207 | div.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
|
237 | p wahoo!
|
238 | ```
|
239 |
|
240 | 它会被渲染为 `<p>wahoo!</p>`.
|
241 |
|
242 | 很帅吧,但是大段的文本怎么办呢:
|
243 |
|
244 | ```jade
|
245 | p
|
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} <#{email}>
|
258 | ```
|
259 |
|
260 | 它会被渲染为 `<div id="user">tj <tj@vision-media.ca></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
|
278 | label
|
279 | | Username:
|
280 | input(name='user[name]')
|
281 | ```
|
282 |
|
283 | 或者直接使用标签文本:
|
284 |
|
285 | ```jade
|
286 | label Username:
|
287 | input(name='user[name]')
|
288 | ```
|
289 |
|
290 | _只_ 包含文本的标签,比如 `<script>`, `<style>`, 和 `<textarea>` 不需要前缀 `|` 字符, 比如:
|
291 |
|
292 | ```jade
|
293 | html
|
294 | head
|
295 | title Example
|
296 | script
|
297 | if (foo) {
|
298 | bar();
|
299 | } else {
|
300 | baz();
|
301 | }
|
302 | ```
|
303 |
|
304 | 这里还有一种选择,可以使用 `.` 来开始一段文本块,比如:
|
305 |
|
306 | ```jade
|
307 | p.
|
308 | foo asdf
|
309 | asdf
|
310 | asdfasdfaf
|
311 | asdf
|
312 | asd.
|
313 | ```
|
314 |
|
315 | 会被渲染为:
|
316 |
|
317 | ```jade
|
318 | <p>foo asdf
|
319 | asdf
|
320 | asdfasdfaf
|
321 | asdf
|
322 | asd
|
323 | .
|
324 | </p>
|
325 | ```
|
326 |
|
327 | 这和带一个空格的 `.` 是不一样的, 带空格的会被 Jade 的解析器忽略,当作一个普通的文字:
|
328 |
|
329 | ```jade
|
330 | p .
|
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
|
348 | p.
|
349 | foo\\bar
|
350 | ```
|
351 |
|
352 | <a name="a6-4"/>
|
353 | ### 注释
|
354 |
|
355 | 单行注释和 JavaScript 里是一样的,通过 `//` 来开始,并且必须单独一行:
|
356 |
|
357 | ```jade
|
358 | // just some paragraphs
|
359 | p foo
|
360 | p bar
|
361 | ```
|
362 |
|
363 | 渲染为:
|
364 |
|
365 | ```html
|
366 | <!-- just some paragraphs -->
|
367 | <p>foo</p>
|
368 | <p>bar</p>
|
369 | ```
|
370 |
|
371 | Jade 同样支持不输出的注释,加一个短横线就行了:
|
372 |
|
373 | ```jade
|
374 | //- will not output within markup
|
375 | p foo
|
376 | p 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
|
392 | body
|
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 |
|
410 | Jade 同样很好的支持了条件注释:
|
411 |
|
412 | ```jade
|
413 | body
|
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 |
|
431 | Jade 支持以自然的方式定义标签嵌套:
|
432 |
|
433 | ```jade
|
434 | ul
|
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
|
449 | ul
|
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
|
461 | html
|
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
|
476 | friends = 5
|
477 |
|
478 | html
|
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 |
|
489 | Jade 现在支持使用 `(` 和 `)` 作为属性分隔符
|
490 |
|
491 | ```jade
|
492 | a(href='/login', title='View login page') Login
|
493 | ```
|
494 |
|
495 | 当一个值是 `undefined` 或者 `null` 属性 _不_ 会被加上,
|
496 | 所以呢,它不会编译出 'something="null"'.
|
497 |
|
498 | ```jade
|
499 | div(something=null)
|
500 | ```
|
501 |
|
502 | Boolean 属性也是支持的:
|
503 |
|
504 | ```jade
|
505 | input(type="checkbox", checked)
|
506 | ```
|
507 |
|
508 | 使用代码的 Boolean 属性只有当属性为 `true` 时才会输出:
|
509 |
|
510 | ```jade
|
511 | input(type="checkbox", checked=someValue)
|
512 | ```
|
513 |
|
514 | 多行同样也是可用的:
|
515 |
|
516 | ```jade
|
517 | input(type='checkbox',
|
518 | name='agreement',
|
519 | checked)
|
520 | ```
|
521 |
|
522 | 多行的时候可以不加逗号:
|
523 |
|
524 | ```jade
|
525 | input(type='checkbox'
|
526 | name='agreement'
|
527 | checked)
|
528 | ```
|
529 |
|
530 | 加点空格,格式好看一点?同样支持
|
531 |
|
532 | ```jade
|
533 | input(
|
534 | type='checkbox'
|
535 | name='agreement'
|
536 | checked)
|
537 | ```
|
538 |
|
539 | 冒号也是支持的:
|
540 |
|
541 | ```jade
|
542 | rss(xmlns:atom="atom")
|
543 | ```
|
544 |
|
545 | 假如我有一个 `user` 对象 `{ id: 12, name: 'tobi' }`
|
546 | 我们希望创建一个指向 `/user/12` 的链接 `href`, 我们可以使用普通的 JavaScript 字符串连接,如下:
|
547 |
|
548 | ```jade
|
549 | a(href='/user/' + user.id)= user.name
|
550 | ```
|
551 |
|
552 | 或者我们使用 Jade 的修改方式, 这个我想很多使用 Ruby 或者 CoffeeScript 的人会看起来像普通的 JS..:
|
553 |
|
554 | ```jade
|
555 | a(href='/user/#{user.id}')= user.name
|
556 | ```
|
557 |
|
558 | `class` 属性是一个特殊的属性,你可以直接传递一个数组,比如 `bodyClasses = ['user', 'authenticated']` :
|
559 |
|
560 | ```jade
|
561 | body(class=bodyClasses)
|
562 | ```
|
563 |
|
564 | <a name="a6-10"/>
|
565 | ### HTML
|
566 |
|
567 | 内联的 HTML 是可以的,我们可以使用管道定义一段文本 :
|
568 |
|
569 | ```jade
|
570 | html
|
571 | body
|
572 | | <h1>Title</h1>
|
573 | | <p>foo bar baz</p>
|
574 | ```
|
575 |
|
576 | 或者我们可以使用 `.` 来告诉 Jade 我们需要一段文本:
|
577 |
|
578 | ```jade
|
579 | html
|
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 | ```
|
596 | html
|
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
|
625 | doctype html
|
626 | ```
|
627 |
|
628 | Doctype 是大小写不敏感的, 所以下面两个是一样的:
|
629 |
|
630 | ```jade
|
631 | doctype Basic
|
632 | doctype basic
|
633 | ```
|
634 |
|
635 | 当然也是可以直接传递一段文档类型的文本:
|
636 |
|
637 | ```jade
|
638 | doctype 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
|
650 | var 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
|
675 | body
|
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 |
|
690 | Jade 目前支持三种类型的可执行代码。第一种是前缀 `-`, 这是不会被输出的:
|
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
|
730 | h1= foo
|
731 | ```
|
732 |
|
733 | 它会渲染为 `bar<h1>bar</h1>`. 为了安全起见,使用 `=` 输出的代码默认是转义的,如果想直接输出不转义的值可以使用 `!=`:
|
734 |
|
735 | ```jade
|
736 | p!= aVarContainingMoreHTML
|
737 | ```
|
738 |
|
739 | Jade 同样是设计师友好的,它可以使 JavaScript 更直接更富表现力。比如下面的赋值语句是相等的,同时表达式还是通常的 JavaScript:
|
740 |
|
741 | ```jade
|
742 | - var foo = 'foo ' + 'bar'
|
743 | foo = 'foo ' + 'bar'
|
744 | ```
|
745 |
|
746 | Jade 会把 `if`, `else if`, `else`, `until`, `while`, `unless` 同别的优先对待, 但是你得记住它们还是普通的 JavaScript:
|
747 |
|
748 | ```jade
|
749 | if foo == 'bar'
|
750 | ul
|
751 | li yay
|
752 | li foo
|
753 | li worked
|
754 | else
|
755 | p oh no! didnt work
|
756 | ```
|
757 |
|
758 | <a name="a9"/>
|
759 | ## 循环
|
760 |
|
761 | 尽管已经支持 JavaScript 原生代码,Jade 还是支持了一些特殊的标签,它们可以让模板更加易于理解,其中之一就是 `each`, 这种形式:
|
762 |
|
763 | ```jade
|
764 | each VAL[, KEY] in OBJ
|
765 | ```
|
766 |
|
767 | 一个遍历数组的例子 :
|
768 |
|
769 | ```jade
|
770 | - var items = ["one", "two", "three"]
|
771 | each 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
|
786 | items = ["one", "two", "three"]
|
787 | each 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
|
802 | obj = { foo: 'bar' }
|
803 | each val, key in obj
|
804 | li #{key}: #{val}
|
805 | ```
|
806 |
|
807 | 将会渲染为:`<li>foo: bar</li>`
|
808 |
|
809 | Jade 在内部会把这些语句转换成原生的 JavaScript 语句,就像使用 `users.forEach(function(user){`, 词法作用域和嵌套会像在普通的 JavaScript 中一样:
|
810 |
|
811 | ```jade
|
812 | each user in users
|
813 | each role in user.roles
|
814 | li= role
|
815 | ```
|
816 |
|
817 | 如果你喜欢,也可以使用 `for` :
|
818 |
|
819 | ```jade
|
820 | for user in users
|
821 | for role in user.roles
|
822 | li= role
|
823 | ```
|
824 |
|
825 | <a name="a10"/>
|
826 | ## 条件语句
|
827 |
|
828 | Jade 条件语句和使用了(`-`) 前缀的 JavaScript 语句是一致的,然后它允许你不使用圆括号,这样会看上去对设计师更友好一点,
|
829 | 同时要在心里记住这个表达式渲染出的是 _常规_ JavaScript:
|
830 |
|
831 | ```jade
|
832 | for 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
|
842 | for user in users
|
843 | - if (user.role == 'admin')
|
844 | p #{user.name} is an admin
|
845 | - else
|
846 | p= user.name
|
847 | ```
|
848 |
|
849 | Jade 同时支持 `unless`, 这和 `if (!(expr))` 是等价的:
|
850 |
|
851 | ```jade
|
852 | for 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 |
|
862 | Jade 支持通过 `block` 和 `extends` 关键字来实现模板继承。 一个块就是一个 Jade 的 block ,它将在子模板中实现,同时是支持递归的。
|
863 |
|
864 | Jade 块如果没有内容,Jade 会添加默认内容,下面的代码默认会输出 `block scripts`, `block content`, 和 `block foot`.
|
865 |
|
866 | ```jade
|
867 | html
|
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
|
882 | extends extend-layout
|
883 |
|
884 | block scripts
|
885 | script(src='/jquery.js')
|
886 | script(src='/pets.js')
|
887 |
|
888 | block content
|
889 | h1= title
|
890 | each pet in pets
|
891 | include pet
|
892 | ```
|
893 |
|
894 | 同样可以在一个子块里添加块,就像下面实现的块 `content` 里又定义了两个可以被实现的块 `sidebar` 和 `primary`,或者子模板直接实现 `content`。
|
895 |
|
896 | ```jade
|
897 | extends regular-layout
|
898 |
|
899 | block 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 |
|
912 | Jade允许你 _替换_ (默认)、 _前置_ 和 _追加_ blocks. 比如,假设你希望在 _所有_ 页面的头部都加上默认的脚本,你可以这么做:
|
913 |
|
914 |
|
915 | ```jade
|
916 | html
|
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
|
929 | extends layout
|
930 |
|
931 | block append head
|
932 | script(src='/vendor/three.js')
|
933 | script(src='/game.js')
|
934 | ```
|
935 |
|
936 | 使用 `block append` 或 `block prepend` 时 `block` 是可选的:
|
937 |
|
938 | ```jade
|
939 | extends layout
|
940 |
|
941 | append head
|
942 | script(src='/vendor/three.js')
|
943 | script(src='/game.js')
|
944 | ```
|
945 |
|
946 | <a name="a13"/>
|
947 | ## 包含
|
948 |
|
949 | Includes 允许你静态包含一段 Jade, 或者别的存放在单个文件中的东西比如 CSS, HTML 非常常见的例子是包含头部和页脚。 假设我们有一个下面目录结构的文件夹:
|
950 |
|
951 | ```
|
952 | ./layout.jade
|
953 | ./includes/
|
954 | ./head.jade
|
955 | ./tail.jade
|
956 | ```
|
957 |
|
958 | 下面是 `layout.jade` 的内容:
|
959 |
|
960 | ```jade
|
961 | html
|
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 | ```
|
991 | html
|
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 |
|
1005 | Include 也可以接受块内容,给定的块将会附加到包含文件 _最后_ 的块里。 举个例子,`head.jade` 包含下面的内容:
|
1006 |
|
1007 | ```jade
|
1008 | head
|
1009 | script(src='/jquery.js')
|
1010 | ```
|
1011 |
|
1012 | 我们可以像下面给`include head`添加内容, 这里是添加两个脚本.
|
1013 |
|
1014 | ```
|
1015 | html
|
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
|
1027 | head
|
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
|
1037 | h1= user.name
|
1038 | p= user.occupation
|
1039 | ```
|
1040 |
|
1041 | 接着,当我们迭代users的时候,只需简单地加上`include user`。因为在循环中`user`变量已经被定义了,被包含的模板可以访问它。
|
1042 |
|
1043 |
|
1044 |
|
1045 | ```jade
|
1046 | users = [{ name: 'Tobi', occupation: 'Ferret' }]
|
1047 |
|
1048 | each 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
|
1065 | each person in users
|
1066 | .user
|
1067 | user = person
|
1068 | include user
|
1069 | ```
|
1070 |
|
1071 |
|
1072 | <a name="a14"/>
|
1073 | ## Mixins
|
1074 |
|
1075 | Mixins 在编译的模板里会被 Jade 转换为普通的 JavaScript 函数。 Mixins 可以还参数,但不是必需的:
|
1076 |
|
1077 | ```jade
|
1078 | mixin list
|
1079 | ul
|
1080 | li foo
|
1081 | li bar
|
1082 | li baz
|
1083 | ```
|
1084 |
|
1085 | 使用不带参数的 mixin 看上去非常简单,在一个块外:
|
1086 |
|
1087 | ```jade
|
1088 | h2 Groceries
|
1089 | mixin list
|
1090 | ```
|
1091 |
|
1092 | Mixins 也可以带一个或者多个参数,参数就是普通的 JavaScript 表达式,比如下面的例子:
|
1093 |
|
1094 | ```jade
|
1095 | mixin pets(pets)
|
1096 | ul.pets
|
1097 | - each pet in pets
|
1098 | li= pet
|
1099 |
|
1100 | mixin 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'
|
1128 | h1.title #{title}
|
1129 | p Just an example
|
1130 | ```
|
1131 |
|
1132 | 当 `compileDebug` 选项不是 `false`, Jade 会编译时会把函数里加上 `__.lineno = n;`, 这个参数会在编译出错时传递给 `rethrow()`, 而这个函数会在 Jade 初始输出时给出一个有用的错误信息。
|
1133 |
|
1134 | ```js
|
1135 | function 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
|
1166 | function 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
|
1191 | JADE = $(shell find pages/*.jade)
|
1192 | HTML = $(JADE:.jade=.html)
|
1193 |
|
1194 | all: $(HTML)
|
1195 |
|
1196 | %.html: %.jade
|
1197 | jade < $< --path $< > $@
|
1198 |
|
1199 | clean:
|
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 |
|
1230 | Examples:
|
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 |
|
1266 | Copyright (c) 2009-2010 TJ Holowaychuk <tj@vision-media.ca>
|
1267 |
|
1268 | Permission is hereby granted, free of charge, to any person obtaining
|
1269 | a copy of this software and associated documentation files (the
|
1270 | 'Software'), to deal in the Software without restriction, including
|
1271 | without limitation the rights to use, copy, modify, merge, publish,
|
1272 | distribute, sublicense, and/or sell copies of the Software, and to
|
1273 | permit persons to whom the Software is furnished to do so, subject to
|
1274 | the following conditions:
|
1275 |
|
1276 | The above copyright notice and this permission notice shall be
|
1277 | included in all copies or substantial portions of the Software.
|
1278 |
|
1279 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
1280 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
1281 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
1282 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
1283 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
1284 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
1285 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|