JST(JavaScript Trimpath)前端模板引擎簡介及應用javascript
今天在作某系統日誌列表的時候用到了這個玩意兒。剛開始只是根據別人的例子照葫蘆畫瓢完成了日誌列表及對應詳情,晚上有空了才仔細去網上找了找對應的資料,細細的品味了一下。如今把應用總結下。html
一、Trimpath簡介前端
Trimpath JavaScript 是個輕量級的,基於JavaScript的,跨瀏覽器,採用APL/GPL開放源代碼協議的,可讓你輕鬆進行基於模板編程方式的純JS引擎。
它有以下的特色:
①、採用標準的JavaScript編寫,支持跨瀏覽器
②、模板語法相似於:FreeMarker,Velocity,Smarty
③、採用簡易的語言來描述大段的字串以及Dom/DHTML操做
採用該引擎,可讓它來徹底處理View方面的事情,服務端Module直接輸出Data就能夠。讓你的MVC模式連成一體,並且因爲View由瀏覽器來處 理,大大減小了服務器的負擔,用來構建Ajax技術的網絡信息系統應用是一個很是好的選擇。java
對應的官方網站是:https://code.google.com/p/trimpath/wiki/JavaScriptTemplates。今天到網站看了一下,貌似這個引擎已經好久沒有更新過了,最新的內容也是2010年的東東。不過還好,用起來還算方便。web
二、簡單應用ajax
廢話很少說了,如今把簡單的應用介紹一下:編程
①第一步在HTML頁面安裝template.js。以下:api
1 <html> 2 <head> 3 <script language="javascript" src="template.js"></script> 4 </head> 5 </html>
②建立數據,這個數據能夠是靜態寫好的數據,也能夠是ajax從服務器端讀來的數據,下面簡單期間採用靜態寫好的數據:數組
1 var data = { 2 products : [ { name: "mac", desc: "computer", 3 price: 1000, quantity: 100, alert:null }, 4 { name: "ipod", desc: "music player", 5 price: 200, quantity: 200, alert:"on sale now!" }, 6 { name: "cinema display", desc: "screen", 7 price: 800, quantity: 300, alert:"best deal!" } ], 8 customer : { first: "John", last: "Public", level: "gold" } 9 };
③建立JST模板以下:瀏覽器
須要符合以下格式:
1 <textarea id="elementId" style="display:none;"> template body </textarea>
下面的是咱們這個例子的模板:
1 <textarea id="cart_jst" style="display:none;"> 2 Hello ${customer.first} ${customer.last}.<br/> 3 Your shopping cart has ${products.length} item(s): 4 <table> 5 <tr><td>Name</td><td>Description</td> 6 <td>Price</td><td>Quantity & Alert</td></tr> 7 {for p in products} 8 <tr><td>${p.name|capitalize}</td><td>${p.desc}</td> 9 <td>$${p.price}</td><td>${p.quantity} : ${p.alert|default:""|capitalize}</td> 10 </tr> 11 {forelse} 12 <tr><td colspan="4">No products in your cart.</tr> 13 {/for} 14 </table> 15 {if customer.level == "gold"} 16 We love you! Please check out our Gold Customer specials! 17 {else} 18 Become a Gold Customer by buying more stuff here. 19 {/if} 20 </textarea>
④下面須要在HTML的body下建立咱們經常使用的holder或者container或者別的你喜歡的名字:
1 <div id="outputDiv"> 2 </div>
⑤編寫對應的核心代碼,其實就簡單的幾行,也是JST的核心函數,以下:
1 <script language="javascript"> 2 //key function 3 var result = TrimPath.processDOMTemplate("cart_jst", data); 4 //instead you can also use next two function 5 var myTemplateObj = TrimPath.parseDOMTemplate("cart_jst"); 6 var result = myTemplateObj.process(data); 7 //display in DOM 8 document.getElementById("outputDiv").innerHTML = result; 9 </script>
其中第三行的代碼與第五行、六行的代碼同樣的功能,在你寫的時候用其中之一便可。
⑥下面是運行結果,固然若是你加上對應的樣式,會更好看的!
1 Hello John Public. 2 Your shopping cart has 3 item(s): 3 Name Description Price Quantity & Alert 4 MAC computer $1000 100 : 5 IPOD music player $200 200 : ON SALE NOW! 6 CINEMA DISPLAY screen $800 300 : BEST DEAL! 7 We love you! Please check out our Gold Customer specials!
三、API
想着本身去翻譯下對應的API,可是去官網下載文檔和JS文件,怎想速度太慢,等了半天都沒下下來,就去網上找了下別人寫好的,只好「拿來」主義了。
附原文地址:http://my.oschina.net/crazyinsomnia/blog/3542
首先到下載頁面下載 template.js
而後在你的JSP/ASP/PHP等文件中引用
CODE:
<script language="javascript" src="trimpath/template.js"></script>
當你引用了template.js文件以後,腳本將建立一個名叫「trimpath"的物件給你使用。
TrimPath Object
這個物件是一個全局的單一變量,也是全部trimpath組件的訪問入口,除了它自身,咱們嘗試創建一個清晰的命名空間給您使用。
下面是 Trimpath 定義的方法:
CODE:
TrimPath.parseDOMTemplate ( elementId, optionalDocument )
獲得頁面中ID爲elementId的Dom組件的InnerHTML,並將其解析成一個模板,這個方法返回一個templateObject對象(下面將詳細描述),解析出錯時將拋出一個異常,下面是這個方法的參數:
elementId DOM組件,其innerhtml將用來作模板
optionalDocument 一個可選參數,在使用iframe,frameset或者默認多文檔時會有用
一般用來作模板的DOM元素是一個隱藏的<textarea>,以下面的例子
CODE:
<textarea id="elementId" style="display:none;"> template body </textarea>
TrimPath.processDOMTemplate ( elementId, contextObject, optionalFlags, optionalDocument )
一 個輔助函數,裏面調用了TrimPath.parseDOMTemplate() 和 then the process() 方法以得到templateObject。輸出的是templateObject.process() 中返回的對象。解析出錯時將拋出一個錯誤。下面是這個方法的參數:
elementId 包含模板內容的DOM元素ID
contextObject 參考templateObject.process()
optionalFlags 參考templateObject.process()
optionalDocument 參考TrimPath.parseDOMTemplate
TrimPath.parseTemplate ( templateContentStr, optionalTemplateName )
解析模板方法,將一個字符串作爲模板解析並返回一個templateObject
參數表:
templateContentStr 符合JST語法的字符串,例如: "Hello ${firstName} ${lastName}"
optionalTemplateName 一個可選的字符串用來指定模板名稱,輔助查錯。
The templateObject
TrimPath.parseTemplate() 和 TrimPath.parseDOMTemplate()的成功運行將產生一個 templateObject 它只有一個主方法
templateObject.process ( contextObject, optionalFlags )
這個方法將模板和數據結合在一塊兒,能夠重複調用,若是沒有從新解析,templateObjects的緩存和重用將得到最好的系統性能。這個函數的返回值是一個通過「渲染」過的模板的字符串。
參數contextObject 必須是一個對象,並將成爲模板的一個訪問域,好比一個模板是:${a},那麼contextObject.a必須是能夠訪問到的。一樣${a.b.c}, contextObject.a.b.c也是能夠訪問到的。
注 意:contextObject 能夠是javascript中的任意對象,包含字符串, 數字, 日期, 對象和函數。因此${groupCalender(new Date())} 能夠這樣來調用contextObject.groupCalender(new Date())。固然,你必須本身編程實現groupCalender() 這個函數。
參數optionalFlags 能夠是空值,也能夠是一個下面列表描述的對象:
throwExceptions 默認是false,當true的時候,process() 方法將從新拋出異常,當false的時候,任何異常將中止解析模板,並在方法返回值包含一個出錯信息。
keepWhitespace 默認是falsel,當值爲true時,模板的空白將保留。當爲false時,空白(換行、空格、TAB)將被截取。
String.prototype.process() 方法
String.prototype.process ( contextObject, optionalFlags )
作爲一個便捷的方式爲string對象加入一個process()的方法,讓它來執行解析模板的動做。參數跟process()同樣。
CODE:
var result = "hello ${firstName}".process(data)
// ...is equivalent to...
var result = TrimPath.parseTemplate("hello ${firstName}").process(data);
添加自定義標識符
若是要採用自定義標識符,你必須把他們放在_MODIFERS 這個對象中,這些標識符集將被添加到contextObject 對象中,而後最終傳給process()解析。每個自定義標識符必須是一個函數而且至少有一個字符串參數輸入和一個字符串輸出。
例子:
CODE:
var myModifiers = {
hello : function(str, greeting) {
if (greeting == null)
greeting = "Hello";
return greeting + ", " + str;
},
zeroSuffix : function(str, totalLength) {
return (str + "000000000000000").substring(0, totalLength);
}
};
var myData = {
firstName : "John",
getCurrentPoints : function() { /* Do something here... */ return 12; }
}
myData._MODIFIERS = myModifiers;
"${firstName}".process(myData) == "John"
"${firstName|hello}".process(myData) == "Hello, John"
"${firstName|hello:"Buenos Dias"}".process(myData) == "Buenos Dias, John"
"${firstName|hello:"Buenos Dias"|capitalize}".process(myData) == "BUENOS DIAS, JOHN"
"${getCurrentPoints()}".process(myData) == "12"
"${getCurrentPoints()|zeroSuffix:4}".process(myData) == "1200"
JST 的語法和語句
語法
CODE:
${expr}
${expr|modifier}
${expr|modifier1|modifier2|...|modifierN}
${expr|modifier1:argExpr1_1}
${expr|modifier1:argExpr1_1,argExpr1_2,...,argExpr1_N}
${expr|modifier1:argExpr1_1,argExpr1_2|...|modifierN:argExprN_1,argExprN_2,...,argExprN_M}
表達式能夠是除了「}」以外的任何合法的javascript字符串
標識符看起來像這種結構:modifierName[:argExpr1[,argExpr2[,argExprN]]]
一個帶參數的表達式例子
CODE:
${customer.firstName}
${customer.firstName|capitalize}
${customer.firstName|default:"no name"|capitalize}
${article.getCreationDate()|default:new Date()|toCalenderControl:"YYYY.MM.DD",true,"Creation Date"}
${(lastQuarter.calcRevenue() - fixedCosts) / 1000000}
一個表達式也能夠像下面同樣經過添加「%」字符來標識,這個能夠避免在你的表達式中出現「}」時出錯的狀況。
好比:
CODE:
Visit our ${% emitLink('Solutions and Products',
{ color: 'red', blink: false }) %} page.
The extra spaces are actually not necessary, like...
${%customer.firstName%}
${%customer.firstName|capitalize%}
語句
JST語句就像是javascript語句同樣,也有if/else/for/function這些句子
分支控制語句
CODE:
{if testExpr}
{elseif testExpr}
{else}
{/if}
上述testExpr 是一個合法的javascript斷定式
例子
CODE:
{if customer != null && customer.balance > 1000}
We love you!
{/if}
{if user.karma > 100}
Welcome to the Black Sun.
{elseif user.isHero}
Sir, yes sir! Welcome!
{if user.lastName == "Yen"}
Fancy some apple pie, sir?
{/if}
{/if}
<a href="/login{if returnURL != null && returnURL != 'main'}?goto=${returnURL}{/if}">Login</a>
*JST引擎還包含一個輔助函數defined(str),這個能夠測試一個變量是否已經被定義。
好比這段代碼判斷管理員發送了消息給你
CODE:
{if defined('adminMessage')}
System Administrator Important NOTICE: ${adminMessage}
{/if}
循環語句
CODE:
{for varName in listExpr}
{/for}
{for varName in listExpr}
...main body of the loop...
{forelse}
...body when listExpr is null or listExpr.length is 0...
{/for}
*varName 必須是一個javascript的合法變量名
*listExpr 能夠是一個數組,對象或者爲空,並且只能被賦值一次
例子
CODE:
Two variables are bound in the main body of the loop:
__LIST__varName - holds the result of evaluating listExpr.
varName_index - this is the key or counter used during iteration.
Examples:
{for x in customer.getRecentOrders()}
${x_index} : ${x.orderNumber} <br/>
{forelse}
You have no recent orders.
{/for}
Converted pseudo-code for the above...
var __LIST__x = customer.getRecentOrders();
if (__LIST__x != null && __LIST__x.length > 0) {
for (var x_index in __LIST__x) {
var x = __LIST__x[x_index];
${x_index} : {$x.orderNumber} <br/>
}
} else {
You have no recent orders.
}
定義變量
{var varName}
{var varName = varInitExpr}
*varName必須是一個合法的javascript變量名
*varInitExpr必須是一個沒有包含"}"的字符串
例子:
CODE:
{var temp = crypto.generateRandomPrime(4096)}
Your prime is ${temp}.
宏定義
{macro macroName(arg1, arg2, ...argN)}
...body of the macro...
{/macro}
*宏相似於一個javascript函數,不一樣點在於宏的主體是另一個包含了諸如控制語句、循環語句的JST模板
*宏的名稱必須是一個合法javascript變量名
*宏的返回值是一個字符創
*使用宏能夠採用這種語法 :${macroName()}
一個使用宏的例子
CODE:
{macro htmlList(list, optionalListType)}
{var listType = optionalListType != null ? optionalListType : "ul"}
<${listType}>
{for item in list}
<li>${item}</li>
{/for}
</${listType}>
{/macro}
Using the macro...
${htmlList([ 1, 2, 3])}
${htmlList([ "Purple State", "Blue State", "Red State" ], "ol")}
{var saved = htmlList([ 100, 200, 300 ])}
${saved} and ${saved}
運行上述語句將出現
QUOTE:
*1
*2
*3
這樣的列表。只需將數據列表賦值給htmlList這個宏,就會幫你把數據經過<li>方式列出來,聰明的你很快就會把它改爲<option><td>等應用了。
從宏的訪問域來講,默認狀況下它是每一個模板私有的,可是若是你想定義
一個宏庫的話,那麼也許你須要在process()以前先定義能夠導出宏:contextObject['exported'] ={};
下面是例子:
CODE:
{macro userName(user)}
{if user.aliasName != null && user.aliasName.length > 0}
${user.aliasName}
{else}
${user.login}
{/if}
{/macro}
${exported.userName = userName |eat}
另外,你也能夠設置 contextObject['exported'] = contextObject;它也能夠正常的工做。
CDATA 文本區段
[code]
{cdata}
...text emitted without JST processing...
{/cdata}
{cdata EOF}
...text emitted without JST processing...
EOF