Node模板引擎學習(2)--Jade語法歸納
Jade語法歸納
把 Jade 編譯為一個可供瀏覽器使用的單檔案,只需要簡單的執行:
make jade.js
如果你已經安裝了 uglifyjs (npm install uglify-js
),你可以執行下面的命令它會生成所有的檔案。其實每一個正式版本里都幫你做了這事。
make jade.min.js
標籤
html
它會被轉換為 <html></html>
#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
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 是可以的,我們可以使用管道定義一段文字 :
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>
Doctypes
新增文件型別只需要簡單的使用 !!!
, 或者 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
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("");
}
Makefile 的一個例子
通過執行 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
使用: 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
相應做了交換
相關文章
- 學習篇:NodeJS中的模板引擎:jadeNodeJS
- 【組合數學】組合數學簡介 ( 組合思想 2 : 數學歸納法 | 數學歸納法推廣 | 多重歸納思想 )
- PHPTAL模板引擎語法PHP
- jQuery學習總結歸納jQuery
- XML與JSON學習歸納XMLJSON
- Kotlin知識歸納(一) —— 基礎語法Kotlin
- HTTP標頭學習總結歸納HTTP
- Blazor和Vue對比學習(基礎1.2):模板語法和Razor語法BlazorVue
- Vue快速上門(2)-模板語法Vue
- UVa11054 Gergovia的酒交易(數學歸納法)Go
- swift學習筆記《2》-swift語法Swift筆記
- 模板語法
- 學習筆記歸納 2010-9-5.10-17筆記
- Django學習——Django settings 原始碼、模板語法之傳值、模板語法之獲取值、模板語法之過濾器、模板語法之標籤、自定義過濾器、標籤、inclusion_tag、模板的匯入、模板的繼承Django原始碼過濾器繼承
- 從“數學歸納法”到理解“遞迴演算法”!遞迴演算法
- Scala學習筆記(2)-基礎語法筆記
- .net 開源模板引擎jntemplate 教程:基礎篇之語法
- Vue模板語法、屬性繫結、條件渲染的學習Vue
- ES6語法學習之字串模板及字串查詢字串
- 007模板語法
- Vue模板語法Vue
- vue 模板語法Vue
- Go 學習筆記 - Go 基礎語法(2)Go筆記
- 基於ts的node專案引入報錯歸納
- MarkDown語法學習
- tensorflow語法學習
- Flask 使用Jinja2模板引擎Flask
- 工具歸納
- R語言學習-迴歸診斷R語言
- 前端學習記錄 1:HTML 基礎知識點歸納前端HTML
- Java SE 語法學習Java
- Flutter Dart語法學習FlutterDart
- Scala基本語法學習
- <node.js學習筆記(2)>Node.js筆記
- 機器學習-學習筆記(一) --> (假設空間 & 版本空間)及 歸納偏好機器學習筆記
- vue簡單模板語法Vue
- 微軟程式歸納新技術:元程式歸納微軟
- openpyxl淺歸納