Jade 是一個高性能的模板引擎,它深受 Haml 影響,它是用 JavaScript 實現的,而且能夠供 Node 使用。javascript
你能夠在網上試玩 Jade。php
!!! 5
文檔類型)filters
修改樹each
枚舉對象、數組甚至是不能枚舉的對象:stylus
必須已經安裝 stylus:less
必須已經安裝 less.js:markdown
必須已經安裝 markdown-js 或者 node-discount:cdata
:coffeescript
必須已經安裝coffee-scriptjade有其餘語言的實現,能夠實現先後端渲染的統一:css
npm install jade
把 Jade 編譯爲一個可供瀏覽器使用的單文件,只須要簡單的執行:html
make jade.js
若是你已經安裝了 uglifyjs (npm install uglify-js
),你能夠執行下面的命令它會生成全部的文件。其實每個正式版本里都幫你作了這事。java
make jade.min.js
默認狀況下,爲了方便調試Jade會把模板組織成帶有形如 __.lineno = 3
的行號的形式。 在瀏覽器裏使用的時候,你能夠經過傳遞一個選項 { compileDebug: false }
來去掉這個。 下面的模板node
p Hello #{name}
會被翻譯成下面的函數:python
function anonymous(locals, attrs, escape, rethrow) { var buf = []; with (locals || {}) { var interp; buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>'); } return buf.join(""); }
經過使用 Jade 的 ./runtime.js
你能夠在瀏覽器使用這些預編譯的模板而不須要使用 Jade, 你只須要使用 runtime.js
裏的工具函數, 它們會放在 jade.attrs
, jade.escape
這些裏。 把選項 { client: true }
傳遞給 jade.compile()
, Jade 會把這些幫助函數的引用放在jade.attrs
, jade.escape
.jquery
function anonymous(locals, attrs, escape, rethrow) { var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow; var buf = []; with (locals || {}) { var interp; buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>'); } return buf.join(""); }
var jade = require('jade'); // Compile a function var fn = jade.compile('string of jade', options); fn(locals);
self
使用 self
命名空間來持有本地變量. (默認爲 false
)locals
本地變量對象filename
異常發生時使用,includes 時必需debug
輸出 token 和翻譯後的函數體compiler
替換掉 jade 默認的編譯器compileDebug
false
的時候調試的結構不會被輸出pretty
爲輸出加上了漂亮的空格縮進 (默認爲 false
)標籤就是一個簡單的單詞:nginx
html
它會被轉換爲 <html></html>
git
標籤也是能夠有 id 的:
div#container
它會被轉換爲 <div id="container"></div>
怎麼加 class 呢?
div.user-details
轉換爲 <div class="user-details"></div>
多個 class 和 id? 也是能夠搞定的:
div#foo.bar.baz
轉換爲 <div id="foo" class="bar baz"></div>
不停的 div div div
很討厭啊 , 能夠這樣:
#foo .bar
這個算是咱們的語法糖,它已經被很好的支持了,上面的會輸出:
<div id="foo"></div><div class="bar"></div>
只須要簡單的把內容放在標籤以後:
p wahoo!
它會被渲染爲 <p>wahoo!</p>
.
很帥吧,可是大段的文本怎麼辦呢:
p
| foo bar baz
| rawr rawr
| super cool | go jade go
渲染爲 <p>foo bar baz rawr.....</p>
怎麼和數據結合起來? 全部類型的文本展現均可以和數據結合起來,若是咱們把 { name: 'tj', email: 'tj@vision-media.ca' }
傳給編譯函數,下面是模板上的寫法:
#user #{name} <#{email}>
它會被渲染爲 <div id="user">tj <tj@vision-media.ca></div>
當就是要輸出 #{}
的時候怎麼辦? 轉義一下!
p \#{something}
它會輸出 <p>#{something}</p>
一樣可使用非轉義的變量 !{html}
, 下面的模板將直接輸出一個 <script>
標籤:
- var html = "<script></script>" | !{html}
內聯標籤一樣可使用文本塊來包含文本:
label | Username: input(name='user[name]')
或者直接使用標籤文本:
label Username: input(name='user[name]')
只 包含文本的標籤,好比 <script>
, <style>
, 和 <textarea>
不須要前綴 |
字符, 好比:
html
head
title Example
script
if (foo) { bar(); } else { baz(); }
這裏還有一種選擇,可使用 .
來開始一段文本塊,好比:
p. foo asdf asdf asdfasdfaf asdf asd.
會被渲染爲:
<p>foo asdf asdf asdfasdfaf asdf asd . </p>
這和帶一個空格的 .
是不同的, 帶空格的會被 Jade 的解析器忽略,看成一個普通的文字:
p .
渲染爲:
<p>.</p>
須要注意的是文本塊須要兩次轉義。好比想要輸出下面的文本:
</p>foo\bar</p>
使用:
p. foo\\bar
單行註釋和 JavaScript 裏是同樣的,經過 //
來開始,而且必須單獨一行:
// just some paragraphs p foo p bar
渲染爲:
<!-- just some paragraphs --> <p>foo</p> <p>bar</p>
Jade 一樣支持不輸出的註釋,加一個短橫線就好了:
//- will not output within markup p foo p bar
渲染爲:
<p>foo</p> <p>bar</p>
塊註釋也是支持的:
body
// #content h1 Example
渲染爲:
<body> <!-- <div id="content"> <h1>Example</h1> </div> --> </body>
Jade 一樣很好的支持了條件註釋:
body
//if IE a(href='http://www.mozilla.com/en-US/firefox/') Get Firefox
渲染爲:
<body> <!--[if IE]> <a href="http://www.mozilla.com/en-US/firefox/">Get Firefox</a> <![endif]--> </body>
Jade 支持以天然的方式定義標籤嵌套:
ul li.first a(href='#') foo li a(href='#') bar li.last a(href='#') baz
塊展開能夠幫助你在一行內建立嵌套的標籤,下面的例子和上面的是同樣的:
ul li.first: a(href='#') foo li: a(href='#') bar li.last: a(href='#') baz
case
表達式按下面這樣的形式寫:
html
body
friends = 10 case friends when 0 p you have no friends when 1 p you have a friend default p you have #{friends} friends
塊展開在這裏也可使用:
friends = 5 html body case friends when 0: p you have no friends when 1: p you have a friend default: p you have #{friends} friends
Jade 如今支持使用 (
和 )
做爲屬性分隔符
a(href='/login', title='View login page') Login
當一個值是 undefined
或者 null
屬性 不 會被加上, 因此呢,它不會編譯出 'something="null"'.
div(something=null)
Boolean 屬性也是支持的:
input(type="checkbox", checked)
使用代碼的 Boolean 屬性只有當屬性爲 true
時纔會輸出:
input(type="checkbox", checked=someValue)
多行一樣也是可用的:
input(type='checkbox', name='agreement', checked)
多行的時候能夠不加逗號:
input(type='checkbox' name='agreement' checked)
加點空格,格式好看一點?一樣支持
input(
type='checkbox' name='agreement' checked)
冒號也是支持的:
rss(xmlns:atom="atom")
假如我有一個 user
對象 { id: 12, name: 'tobi' }
咱們但願建立一個指向 /user/12
的連接 href
, 咱們可使用普通的 JavaScript 字符串鏈接,以下:
a(href='/user/' + user.id)= user.name
或者咱們使用 Jade 的修改方式, 這個我想不少使用 Ruby 或者 CoffeeScript 的人會看起來像普通的 JS..:
a(href='/user/#{user.id}')= user.name
class
屬性是一個特殊的屬性,你能夠直接傳遞一個數組,好比 bodyClasses = ['user', 'authenticated']
:
body(class=bodyClasses)
內聯的 HTML 是能夠的,咱們可使用管道定義一段文本 :
html
body
| <h1>Title</h1> | <p>foo bar baz</p>
或者咱們可使用 .
來告訴 Jade 咱們須要一段文本:
html
body.
<h1>Title</h1> <p>foo bar baz</p>
上面的兩個例子都會渲染成相同的結果:
<html><body><h1>Title</h1> <p>foo bar baz</p> </body></html>
這條規則適應於在 Jade 裏的任何文本:
html body h1 User <em>#{name}</em>
添加文檔類型只須要簡單的使用 !!!
, 或者 doctype
跟上下面的可選項:
!!!
會渲染出 transitional 文檔類型, 或者:
!!! 5
或
!!! html
或
doctype html
Doctype 是大小寫不敏感的, 因此下面兩個是同樣的:
doctype Basic doctype basic
固然也是能夠直接傳遞一段文檔類型的文本:
doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
渲染後:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN">
會輸出 HTML5 文檔類型. 下面的默認的文檔類型,能夠很簡單的擴展:
var doctypes = exports.doctypes = {
'5': '<!DOCTYPE html>', 'xml': '<?xml version="1.0" encoding="utf-8" ?>', 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">', 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">', 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">', '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">', 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">', 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">' };
經過下面的代碼能夠很簡單的改變默認的文檔類型:
jade.doctypes.default = 'whatever you want';
過濾器前綴 :
, 好比 :markdown
會把下面塊裏的文本交給專門的函數進行處理。查看頂部 特性 裏有哪些可用的過濾器。
body :markdown Woah! jade _and_ markdown, very **cool** we can even link to [stuff](http://google.com)
渲染爲:
<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>
Jade 目前支持三種類型的可執行代碼。第一種是前綴 -
, 這是不會被輸出的:
- var foo = 'bar';
這能夠用在條件語句或者循環中:
- for (var key in obj) p= obj[key]
因爲 Jade 的緩存技術,下面的代碼也是能夠的:
- if (foo) ul li yay li foo li worked - else p oh no! didnt work
哈哈,甚至是很長的循環也是能夠的:
- if (items.length) ul - items.forEach(function(item){ li= item - })
因此你想要的!
下一步咱們要 轉義 輸出的代碼,好比咱們返回一個值,只要前綴一個 =
:
- var foo = 'bar' = foo h1= foo
它會渲染爲 bar<h1>bar</h1>
. 爲了安全起見,使用 =
輸出的代碼默認是轉義的,若是想直接輸出不轉義的值可使用 !=
:
p!= aVarContainingMoreHTML
Jade 一樣是設計師友好的,它可使 JavaScript 更直接更富表現力。好比下面的賦值語句是相等的,同時表達式仍是一般的 JavaScript:
- var foo = 'foo ' + 'bar' foo = 'foo ' + 'bar'
Jade 會把 if
, else if
, else
, until
, while
, unless
同別的優先對待, 可是你得記住它們仍是普通的 JavaScript:
if foo == 'bar' ul li yay li foo li worked else p oh no! didnt work
儘管已經支持 JavaScript 原生代碼,Jade 仍是支持了一些特殊的標籤,它們可讓模板更加易於理解,其中之一就是 each
, 這種形式:
each VAL[, KEY] in OBJ
一個遍歷數組的例子 :
- var items = ["one", "two", "three"] each item in items li= item
渲染爲:
<li>one</li> <li>two</li> <li>three</li>
遍歷一個數組同時帶上索引:
items = ["one", "two", "three"] each item, i in items li #{item}: #{i}
渲染爲:
<li>one: 0</li> <li>two: 1</li> <li>three: 2</li>
遍歷一個數組的鍵值:
obj = { foo: 'bar' } each val, key in obj li #{key}: #{val}
將會渲染爲:<li>foo: bar</li>
Jade 在內部會把這些語句轉換成原生的 JavaScript 語句,就像使用 users.forEach(function(user){
, 詞法做用域和嵌套會像在普通的 JavaScript 中同樣:
each user in users each role in user.roles li= role
若是你喜歡,也可使用 for
:
for user in users for role in user.roles li= role
Jade 條件語句和使用了(-
) 前綴的 JavaScript 語句是一致的,而後它容許你不使用圓括號,這樣會看上去對設計師更友好一點, 同時要在內心記住這個表達式渲染出的是 常規 JavaScript:
for user in users if user.role == 'admin' p #{user.name} is an admin else p= user.name
和下面的使用了常規 JavaScript 的代碼是相等的:
for user in users - if (user.role == 'admin') p #{user.name} is an admin - else p= user.name
Jade 同時支持 unless
, 這和 if (!(expr))
是等價的:
for user in users unless user.isAnonymous p | Click to view a(href='/users/' + user.id)= user.name
Jade 支持經過 block
和 extends
關鍵字來實現模板繼承。 一個塊就是一個 Jade 的 block ,它將在子模板中實現,同時是支持遞歸的。
Jade 塊若是沒有內容,Jade 會添加默認內容,下面的代碼默認會輸出 block scripts
, block content
, 和 block foot
.
html head h1 My Site - #{title} block scripts script(src='/jquery.js') body block content block foot #footer p some footer content
如今咱們來繼承這個佈局,簡單建立一個新文件,像下面那樣直接使用 extends
,給定路徑(能夠選擇帶 .jade
擴展名或者不帶). 你能夠定義一個或者更多的塊來覆蓋父級塊內容, 注意到這裏的 foot
塊 沒有 定義,因此它還會輸出父級的 "some footer content"。
extends extend-layout block scripts script(src='/jquery.js') script(src='/pets.js') block content h1= title each pet in pets include pet
一樣能夠在一個子塊裏添加塊,就像下面實現的塊 content
裏又定義了兩個能夠被實現的塊 sidebar
和 primary
,或者子模板直接實現 content
。
extends regular-layout block content .sidebar block sidebar p nothing .primary block primary p nothing
Jade容許你 替換 (默認)、 前置 和 追加 blocks. 好比,假設你但願在 全部 頁面的頭部都加上默認的腳本,你能夠這麼作:
html head block head script(src='/vendor/jquery.js') script(src='/vendor/caustic.js') body block content
如今假設你有一個Javascript遊戲的頁面,你但願在默認的腳本以外添加一些遊戲相關的腳本,你能夠直接append
上代碼塊:
extends layout block append head script(src='/vendor/three.js') script(src='/game.js')
使用 block append
或 block prepend
時 block
是可選的:
extends layout append head script(src='/vendor/three.js') script(src='/game.js')
Includes 容許你靜態包含一段 Jade, 或者別的存放在單個文件中的東西好比 CSS, HTML 很是常見的例子是包含頭部和頁腳。 假設咱們有一個下面目錄結構的文件夾:
./layout.jade
./includes/ ./head.jade ./tail.jade
下面是 layout.jade
的內容:
html
include includes/head body h1 My Site p Welcome to my super amazing site. include includes/foot
這兩個包含 includes/head
和 includes/foot
都會讀取相對於給 layout.jade
參數filename
的路徑的文件, 這是一個絕對路徑,不用擔憂Express幫你搞定這些了。Include 會解析這些文件,而且插入到已經生成的語法樹中,而後渲染爲你期待的內容:
<html> <head> <title>My Site</title> <script src="/javascripts/jquery.js"> </script><script src="/javascripts/app.js"></script> </head> <body> <h1>My Site</h1> <p>Welcome to my super lame site.</p> <div id="footer"> <p>Copyright>(c) foobar</p> </div> </body> </html>
前面已經提到,include
能夠包含好比 HTML 或者 CSS 這樣的內容。給定一個擴展名後,Jade 不會把這個文件看成一個 Jade 源代碼,而且會把它看成一個普通文本包含進來:
html
head
//- css and js have simple filters that wrap them in <style> and <script> tags, respectively include stylesheet.css include script.js body //- "markdown" files will use the "markdown" filter to convert Markdown to HTML include introduction.markdown //- html files have no filter and are included verbatim include content.html
Include 也能夠接受塊內容,給定的塊將會附加到包含文件 最後 的塊裏。 舉個例子,head.jade
包含下面的內容:
head script(src='/jquery.js')
咱們能夠像下面給include head
添加內容, 這裏是添加兩個腳本.
html include head script(src='/foo.js') script(src='/bar.js') body h1 test
在被包含的模板中,你也可使用yield
語句。yield
語句容許你明確地標明include
的代碼塊的放置位置。好比,假設你但願把代碼塊放在scripts以前,而不是附加在scripts以後:
head yield script(src='/jquery.js') script(src='/jquery.ui.js')
因爲被包含的Jade會按字面解析併合併到AST中,詞法範圍的變量的效果和直接寫在同一個文件中的相同。這就意味着include
能夠用做partial的替代,例如,假設咱們有一個引用了user
變量的user.jade`文件:
h1= user.name p= user.occupation
接着,當咱們迭代users的時候,只需簡單地加上include user
。由於在循環中user
變量已經被定義了,被包含的模板能夠訪問它。
users = [{ name: 'Tobi', occupation: 'Ferret' }] each user in users .user include user
以上代碼會生成:
<div class="user"> <h1>Tobi</h1> <p>Ferret</p> </div>
user.jade
引用了user
變量,若是咱們但願使用一個不一樣的變量user
,那麼咱們能夠直接定義一個新變量user = person
,以下所示:
each person in users .user user = person include user
Mixins 在編譯的模板裏會被 Jade 轉換爲普通的 JavaScript 函數。 Mixins 能夠帶參數,但不是必需的:
mixin list ul li foo li bar li baz
使用不帶參數的 mixin 看上去很是簡單,在一個塊外:
h2 Groceries mixin list
Mixins 也能夠帶一個或者多個參數,參數就是普通的 JavaScript 表達式,好比下面的例子:
mixin pets(pets) ul.pets - each pet in pets li= pet mixin profile(user) .user h2= user.name mixin pets(user.pets)
會輸出像下面的 HTML:
<div class="user"> <h2>tj</h2> <ul class="pets"> <li>tobi</li> <li>loki</li> <li>jane</li> <li>manny</li> </ul> </div>
假設咱們有下面的 Jade 源碼:
- var title = 'yay' h1.title #{title} p Just an example
當 compileDebug
選項不是 false
, Jade 會編譯時會把函數里加上 __.lineno = n;
, 這個參數會在編譯出錯時傳遞給 rethrow()
, 而這個函數會在 Jade 初始輸出時給出一個有用的錯誤信息。
function anonymous(locals) { var __ = { lineno: 1, input: "- var title = 'yay'\nh1.title #{title}\np Just an example", filename: "testing/test.js" }; var rethrow = jade.rethrow; try { var attrs = jade.attrs, escape = jade.escape; var buf = []; with (locals || {}) { var interp; __.lineno = 1; var title = 'yay' __.lineno = 2; buf.push('<h1'); buf.push(attrs({ "class": ('title') })); buf.push('>'); buf.push('' + escape((interp = title) == null ? '' : interp) + ''); buf.push('</h1>'); __.lineno = 3; buf.push('<p>'); buf.push('Just an example'); buf.push('</p>'); } return buf.join(""); } catch (err) { rethrow(err, __.input, __.filename, __.lineno); } }
當 compileDebug
參數是 false
, 這個參數會被去掉,這樣對於輕量級的瀏覽器端模板是很是有用的。結合 Jade 的參數和當前源碼庫裏的 ./runtime.js
文件,你能夠經過 toString()
來編譯模板而不須要在瀏覽器端運行整個 Jade 庫,這樣能夠提升性能,也能夠減小載入的 JavaScript 數量。
function anonymous(locals) { var attrs = jade.attrs, escape = jade.escape; var buf = []; with (locals || {}) { var interp; var title = 'yay' buf.push('<h1'); buf.push(attrs({ "class": ('title') })); buf.push('>'); buf.push('' + escape((interp = title) == null ? '' : interp) + ''); buf.push('</h1>'); buf.push('<p>'); buf.push('Just an example'); buf.push('</p>'); } return buf.join(""); }
經過執行 make
, 下面的 Makefile 例子能夠把 pages/*.jade
編譯爲 pages/*.html
。
JADE = $(shell find pages/*.jade) HTML = $(JADE:.jade=.html) all: $(HTML) %.html: %.jade jade < $< --path $< > $@ clean: rm -f $(HTML) .PHONY: clean
這個能夠和 watch(1)
命令起來產生像下面的行爲:
$ watch make
使用: jade [options] [dir|file ...] 選項: -h, --help 輸出幫助信息 -v, --version 輸出版本號 -o, --out <dir> 輸出編譯後的 HTML 到 <dir> -O, --obj <str> JavaScript 選項 -p, --path <path> 在處理 stdio 時,查找包含文件時的查找路徑 -P, --pretty 格式化 HTML 輸出 -c, --client 編譯瀏覽器端可用的 runtime.js -D, --no-debug 關閉編譯的調試選項(函數會更小) -w, --watch 監視文件改變自動刷新編譯結果 Examples: # 編譯整個目錄 $ jade templates # 生成 {foo,bar}.html $ jade {foo,bar}.jade # 在標準IO下使用jade $ jade < my.jade > my.html # 在標準IO下使用jade, 同時指定用於查找包含的文件 $ jade < my.jade -p my.jade > my.html # 在標準IO下使用jade $ echo "h1 Jade!" | jade # foo, bar 目錄渲染到 /tmp $ jade foo bar --out /tmp
注意: 從 v0.31.0
的 -o
選項已經指向 --out
, -O
相應作了交換