Leaf是一種模板語言卡者,目的就是使視圖渲染更加容易。其實在其他服務(wù)端開發(fā)過程中也經(jīng)常使用模板棺亭,比如Mustache
虎眨、Express
蟋软。
Leaf作為一種可擴展的模板語言镶摘,專用于Vapor,至于其與其他模板的區(qū)別以及原理我暫時沒有研究岳守,咳咳凄敢,我們還是先學(xué)習(xí)怎么使用吧。
Synax(語法)
Structure
Leaf標(biāo)簽由四個元素構(gòu)成:
- Token:
#
就是Leaf的標(biāo)識 - Name:用字符串來區(qū)分這個標(biāo)簽
- Parameter List:
()
可以接收0到多個參數(shù) - Body(可選):
{}
必須用空格與Parameter List
分開
根據(jù)標(biāo)簽的實現(xiàn)湿痢,這4個元素可以有很多不同的用法涝缝。我們來看幾個例子扑庞,說明如何使用Leaf的內(nèi)置標(biāo)簽:
#()
#(variable)
#import("template")
#export("link") { <a href="#()"></a> }
#index(friends, "0")
#loop(friends, "friend") { <li>#(friend.name)</li> }
#raw() { <a href="#raw">Anything goes @#$%^&*</a> }
Using the #
token in HTML
#
無法轉(zhuǎn)義,在Leaf模板中要使用#()
或 #raw() {}
來輸出#
拒逮。#()
=> #
Raw HTML
任何Leaf模板的輸出都默認被轉(zhuǎn)義罐氨,如果不想被轉(zhuǎn)義輸出可以使用#raw()
標(biāo)簽。#raw() { <a href="#link">Link</a> }
=><a href="#link">Link</a>
<i><b>ps:</b>這里體現(xiàn)了Leaf選擇用#
作為標(biāo)簽的缺點滩援,很容易與html中的鏈接沖突栅隐。</i>
Chaining(鏈接)
##
表示鏈接標(biāo)簽,可以用在任何標(biāo)準(zhǔn)標(biāo)簽上玩徊,如果前一個標(biāo)簽失敗租悄,就會執(zhí)行鏈接的標(biāo)簽。
#if(hasFriends) ##embed("getFriends")
上面代碼中恩袱,如果#if(hasFriends)
調(diào)用失敗泣棋,就調(diào)用#embed("getFriends")
(也就是沒friends的話就去獲取friends)。
Leaf's build-in Tags(Leaf內(nèi)置標(biāo)簽)
- Token:
#()
#() #()hashtags #()FTW => # #Hashtags #FTW
- Raw:
#raw() {}
,body部分不會被Leaf轉(zhuǎn)義渲染
#raw() {
Do whatever w/ #'s here, this code won't be rendered as leaf document and is not escaped.
It's a great place for things like Javascript or large HTML sections.
}
- Equal:
#equal(lhs,rhs) {}
用于判斷body內(nèi)的表達式是否成立畔塔。
#equal(leaf, leaf) { Leaf == Leaf } => Leaf == Leaf
#equal(leaf, mustache) { Leaf == Mustache } => Leaf == Mustache
- Variable:
#(variable)
變量
Hello, #(name)!
- Loop: #loop(object, "index") 循環(huán)潭辈,相當(dāng)于
for item in object
#loop(friends, "friend") {
Hello, #(friend.name)!
}
- Index:
#index(object, _ index: Int|String)
用下標(biāo)或鍵取值
Hello, #index(friends, 0)!
Hello, #index(friends, "best")!
- If-Else:
#if(Bool) ##else(){ this }
"if... else...",需要注意的是else if
也是用#if()
表示俩檬。
#if(entering) {
Hello, there!
} ##if(leaving) {
Goodbye!
} ##else() {
I've been here the whole time.
}
- Import:
#import("template")
設(shè)置插入點 - Export:
#export("template") { Leaf/HTML }
在插入點處引入木本內(nèi)容 - Extend:
#extend("template")
繼承模板萎胰,使用模板內(nèi)容 - Embed:
#embed("template")
將模板內(nèi)容插入到當(dāng)前位置
使用這些標(biāo)簽的引入模板的時候不用加
.leaf
后綴。
這么說你是不是懵逼了棚辽?還吃吃個??吧:
/// base.leaf
<!DOCTYPE html>
#import("html")
/// html.leaf
#extend("base")
#export("html") { <html>#embed("body")</html> }
/// body.leaf
<body></body>
Leaf最后會將html.leaf
按照如下內(nèi)容渲染:
<!DOCTYPE html>
<html><body></body></html>
我給你剝下栗子皮:
1技竟,base.leaf
用#import("html")
設(shè)置了一個插入點,點名使用名為"html.leaf"的模板去填充屈藐。
2榔组,html.leaf
用#extend("base")
表明我繼承base.leaf
,要引入base.leaf
的內(nèi)容联逻。
3搓扯,#export("html"){...}
就是將{...}
中的內(nèi)容填充到base.leaf
中插入點位置。
4包归,#embed("body")
就是把body.leaf
模板的內(nèi)容直接嵌入到當(dāng)前位置锨推。
Custom Tags(自定義標(biāo)簽)
內(nèi)置標(biāo)簽肯定無法滿足各種復(fù)雜場景的需要,當(dāng)然也滿足不了你膨脹的內(nèi)心公壤,所以自定義標(biāo)簽?zāi)愕脮伞?br>
看一下現(xiàn)在存在的高級場景應(yīng)用的標(biāo)簽换可,一起學(xué)習(xí)一下創(chuàng)建 Index
標(biāo)簽的基礎(chǔ)示例,它接收兩個參數(shù)厦幅,一個是數(shù)組沾鳄,一個是索引的下標(biāo):
class Index: BasicTag {
let name = "index"
func run(arguments: [Argument]) throws -> Node? {
guard
arguments.count == 2,
let array = arguments[0].value?.nodeArray,
let index = arguments[1].value?.int,
index < array.count
else { return nil }
return array[index]
}
}
然后將這個標(biāo)簽注冊到main.swift
中:
if let leaf = drop.view as? LeafRenderer {
leaf.stem.register(Index())
}
<i><b>ps:</b>Dependencies/Leaf 1.0.7/Leaf/Tag/Models/
目錄下有每個內(nèi)置標(biāo)簽類的實現(xiàn)過程。</i>
Note: 不推薦使用除字母或數(shù)字之外的字符作為標(biāo)簽名确憨,并且在未來的Leaf版本中可能會禁止使用译荞。
Syntax Highlighting
語法高亮這部分不多說了瓤的,Atom編輯器支持Leaf語法。Xcode不支持吞歼,可以Editor > Syntax Coloring > HTML
改成html語法略微改善圈膏。