在ASP.NET MVC利用PagedList分頁(二)PagedList+Ajax+JsRender中提到了JsRender。JsRedner和JsViews(JsViews是再JsRender基礎上的進一步封裝)被稱為下一代的Jquery模板,官方地址:https://github.com/BorisMoore/jsrender;https://github.com/BorisMoore/jsviews。Juqrey模板是一個javascript引擎(抄的、這個東東太高深了),他最直接的作用就是:1、代碼重用,減少代碼量;(貌似還更容易編寫)2、拋棄繁瑣的字符串拼接、提高代碼可見性、簡化維護。
為什么需要模板
總之,我是寫過無數這樣蛋疼的代碼:
var html = '';
$.each(data.persons, function (i, item) { html += "<tr><td>" + item.FirstName + "</td><td><a href='/Person/Edit/"
+ item.PersonID + "'>Edit</a> | <a href='/Person/Details/"
+ item.PersonID + "'>Details</a> | <a href='/Person/Delete/"
+ item.PersonID + "'>Delete</a></td></tr>"; });
$('#XXX').append(html);
如果覺得這樣還是不明顯,可以參見ASP.NET MVC利用PagedList分頁(二)PagedList+Ajax+JsRender中的第四部分,這樣寫很明顯的壞處就是:這樣的代碼可見性太低,很難維護。或許你幾個月之后再來看你的代碼,你要花半個小時甚至更多才能得出代碼的展示結構。下面來看個JsRender的例子:
//Templates <script type="text/x-jsrender" id="personListTemplate"> {{for persons}} <tr> <td>{{:FirstName}}</td> <td> <a href="/Person/Edit/{{:PersonID}}">Edit</a> | <a href="/Person/Details/{{:PersonID}}">Details</a> | <a href="/Person/Delete/{{:PersonID}}">Delete</a> </td> </tr> {{/for}} </script> //Render Data var html = $("#personListTemplate").render(data); //Insert into Container $("#XXX").append(html);
代碼的結構確實清晰可見了,但是代碼越看越多了。首先,這是錯覺,因為這里的東東都是嚴格換行了的。其次,這里省去了item、each等字符復雜字符,貌似更容易編寫了。
JsRender和Jquery Template
既然JsRender是下一代Jquery模板,那么誰是上一代模板呢?Jquery Template。Jquery Template的特點這里就不廢話了,說說JsRedner和Jquery Template的差距:
1、JsRender渲染非常快,網上說的是“和最快一樣快”(當然我也不知道他到底有多快)。對於簡單的模板的渲染,JsRender的渲染速度比Js Template可以快20倍。
2、JsRender對Dom和Jquery不存在任何依賴(注:不依賴並不是說不使用...)。在Jquery Template 必須用$.template(name,'XXX')標記模板,然后渲染。JsRedner不用,他甚至可以直接渲染字符串。
3、JsRender和Jquery Template相比,JsRender僅僅需要更少的代碼,2就是一個例子。
JsRender三要素和行為
從上面貼的代碼可以看出,JsRender需要三要素:模板(Template)、容器(Container:簡單。。。)、數據(Data:數據可以使各種js對象:如數組,object等等)。主要行為為:渲染模板、將渲染結果插入容器(這個太簡單了)。說下渲染模板先。。。
JsRender渲染模板
1、無需編譯直接渲染:
var html = $("#XXXXX").render(data); // XXX代表某個腳本標記,也就是上面的<script id="XXX" type="text/x-jsrender">.......</script>
2、渲染前編譯:
/*A、獲取模板對象的方式編譯*/ var xxxTemplate = $.templates("#xxxTemplate");//既可以是字符串也可以是腳本標記,B是字符串 var html = xxxTemplate.render(data); /*B、指定模板名稱的方式編譯*/ $.templates('xxx','<b>{{:name}}</b>');
$.templates({
'yyy','<b>{{:name}}</b>',
'zzz','<b>{{:name}}</b>'
}); var html = $.render.xxx(data);//注意,第B種方式可以同時渲染多個模板,但是第A種方式不行
總結一下可以看出:1、無編譯直接渲染的方式無法用於字符串的渲染;渲染前編譯的方式字符串和腳本標記皆可。2、制定模板名稱的方式編譯可以同時編譯多個模板,但是獲取模板對象的方式編譯只能編譯一個模板。
JsRender模板(Template)
基本的jsRender標簽:JsRender模板主要由html標記和jsrender標簽(像上面的{{:XXX}})組成。所有的Jsrender標簽都被兩個大括號包裹,中間既可以是參數也可以使表達式(如:{{:#index}}和{{:#index+1}}),下面看一下一些基本的Jsrender標簽。
描述 | 例子 | 輸出 |
參數firstName的值(未被Html編碼) | {{:firstName}} | Madelyn |
參數movie的屬性--releaseYear的值(未被html編碼) | {{:movie.releaseYear}} | 1987 |
比較(表達式,未被html編碼) | {{:movie.releaseYear < 2000}} | true |
經html編碼的值(更加安全,但是要耗點內存) | {{>movie.name}} | Star Wars: Episode VI: <span style='color:purple;font-style: italic;'>Return of the Jedi</span> |
經html編碼的值 | {{html:movie.name}} | Star Wars: Episode VI: <span style='color:purple;font-style: italic;'>Return of the Jedi</span> |
jsrender數據遍歷:看過ASP.NET MVC利用PagedList分頁(二)PagedList+Ajax+JsRender的童鞋對jsrender的數據遍歷相信不會陌生,基本語法如下:
{{for xxx}} <li>{{:property of xxx}}</li> {{/for}}
有時候想獲取xxx本身怎么辦呢?如下:
{{for xxx yyy}} <li>{{:#data}}</li> {{/for}}
上面的例子要說明兩點:1、for不僅僅可以遍歷一組數據,他甚至可以同時遍歷兩組和多組數據(強大了吧...)。2、上面的#data就表示xxx和yyy本生。試想一下,如何xxx和yyy都表示一個基本元素(字符串、整數等等、任意交叉)的數組,那么這個是不是能很好的完成遍歷呢?說道#data,不得不提一下#index,#data和#index都是內置的jsrender關鍵字。下面在一個例子:
//Template {{for #data}} <h3>{{:name}}</h3> <ul> {{for language}} <li> {{:#parent.parent.data.name}} is learning {{:title}}</li> {{/for}} </ul> {{/for}} //Data var studnets = [ { "name": "Mingjun Tang", "language": [{ "title": "English"},{ "title": "Franch"}] }, { "name": "Ming Tang", "language": [{ "title": "English"}] } ];
遍歷時#data充當了students,同時#parent.parent.data.XXX可以用於向上迭代。注意這里的data並不是student中的屬性額,因為#parent向上迭代后返回的是一個jsrender對象只有,#parent.data后才會返回數組內容。#parent在jsrender叫路徑訪問,但是我覺得這里叫向上迭代還要好些。
jsrender條件:
{{if fullprice}} html markup {{else halfprice}} html markup {{else}} html markup {{/if}}
也可以吧他們扯開用,如:{{if fullprice}}html markup{{/if}}和{{if fullprice}}html markup{{else}}html markup{{/if}}。但是這里需要注意兩點:
1、if....else....else表示了if elseif else,這里的else表示了elseif。
2、{{if fullprice}}中的fullprice條件表達式表示的是fullprice不為空。其實還可以有更懂的條件表達式可以應用到這里來,如下(注意這里的等於和不等於、、、、):
表達式 | 舉例 | 注釋 |
|| | {{ :a || b }} | 或 |
&& | {{ :a && b }} | 且 |
! | {{ :!a }} | 非 |
<= 和>=和 <和 > | {{ :a <= b }} | 比較 |
=== 和 !== | {{ :a === b }} | 等於和不等於 |
3、在條件表達式中還可以用一些屬性進行比較,如{{if xxx.length > 50}}等等
jsrender模板嵌套:
在上面一個例子中,嵌套了兩個for循環,試想一下,如果這兩個for循環結構非常復雜或其下還要嵌套一個甚至多個for循環的時候,上面所說的jsrender提高了代碼的可見性和可維護性就不復存在了。於是jsrender也提供了jsrender模板的嵌套,改寫一下上上面的JsRender模板:
<script type="text/x-jsrender" id="studentTemplate"> {{for #data}} <h3>{{:name}}</h3> <ul> {{for language tmpl="#studentLanguageTemplate" /}} </ul> {{/for}} </script> <script type="text/x-jsrender" id="studentLanguageTemplate"> <li> {{:#parent.parent.data.name}} is learning {{:title}}</li> </script>
//render
$("#studentList").html($("#studentTemplate").render(studnets));
這樣就可以避免無限的嵌套下去,只需要設置{{for}}的tmpl屬性即可。這時,tmpl是一個腳本標記。如果studentLanguageTemplate已經被$.templates()編譯,那么也可以這么寫:
<script type="text/x-jsrender" id="studentTemplate"> {{for #data}} <h3>{{:name}}</h3> <ul> {{for language tmpl="studentLanguageTemplate" /}} </ul> {{/for}} </script> <script type="text/x-jsrender" id="studentLanguageTemplate"> <li> {{:#parent.parent.data.name}} is learning {{:title}}</li> </script> //render $.templates("studentLanguageTemplate", "#studentLanguageTemplate"); $("#studentList").html($("#studentTemplate").render(studnets));
上面的templ不再“#XXX”指向一個腳本標記,而是"XXX"指向一個已經標記的腳本標記。(哈哈 說起來還真繞口)。
OK,基礎的東東就差不多了。不過除了着了,Jsrender還具備良好的可擴展性。后頭在慢慢來看看。。。。。
補充:
有些朋友在問jsrender現在是否適合用於項目,看官網介紹:
Warning: JsRender is close to beta, but not yet officially beta, so there may still be changes to APIs and features in the coming period.
jsrender雖然接近測試版,但是還不是正式的測試版。所以它的API或一些功能可能還是會有改動。也就是說jsrender的穩定性可能還不是十分確定,所以如果正式的項目還是建議大家使用Jquery Template。