1.前言
從后台獲取數據,在前端JS里面拼接字符串,不累嗎?敢不敢找一款前端使使。。。
現在這種模板庫比較多了,我用過的jquery-template 、JsRender 、聽說過的一堆,還有各種MVC庫里面帶的各種模板庫,之前看到有人介紹kino.razor這個,一看源代碼,就幾百行,以前用過的那些template engine,好奇怎么出來的。就借這個機會研究研究,自己模仿者造一個。它源碼少啊。。。
2.kino.razor模版庫原理,流程分析
怎么使用http://www.cnblogs.com/Music/p/kino-razor.html這篇里有介紹 , 前台模板寫成

1 <script type="text/template"> 2 @{ 3 //code block... 4 var data=10; 5 } 6 7 @for(var i=10;i<data;i++) 8 { 9 <div>@(i)</div> 10 } 11 </script>
這種js代碼與html混在一起的,是怎么實現的呢。。。
首先分析這種template要認識到,有兩種模式,即js code 模式,和 html代碼模式。在code模式中,@{ code block}這種,就是要執行的代碼,不會產生模版生成的內容,另一種就是引用變量了,在<div>@(variable)</div>這里,這個@(variable)同<div> </div>一樣,會被生成到 模板引擎 生成的html中。這么說有點抽象。所以說,有三種狀態1.代碼塊 2.普通string,最后生成到html 3.變量,需要執行並申城到html里
在拿到templateString之后,模板引擎會一個字一個字的掃描,處理,碰到@{}這樣的代碼塊,它就需要在一個context中執行,以保存其中的變量呢,碰到普通的string,像<div>這種,直接放到結果集中,對於@(variable)需要在這個context中解釋一下,這個值說不定就是前面code block中聲明的,再放到結果集中。
就像這樣一個 模板,可以使用kino.razor(template,model);這個model對象是傳進去的,要被模板利用,就同樣需要這樣的context,那么誰來提供這樣一個context呢???我是看了源碼,這個模板字符串最終會被編譯成一個函數,就是var func=某種方法(string template),將string變成一個function,然后這個model,傳給func,即func(model)就會得到輸出的html
編譯出的函數會是啥樣
function func(model){
var result=[];
//在@{}這樣的code block中全是code,直接放到 這里運行
var data=10;
//@for(){ }
在for while循環里面默認是String模式,就是可以直接寫<div>引用變量要寫@符號
for(var i=0;i<10;i++)
{
//在循環內部,String 輸出內容,我們構建一個數組result 來裝 要生成的內容
//碰到<div>
result.push("<div>");
//碰到@(i)
result.push(i);//變量,在當前context取值,並放到生成結果集中
//碰到</div>,放到result
result.push("</div>")
}
}
這樣就達到了循環的目的。可是這樣的期望函數咋生成???JS里面有 new Function(parameter0,...parametern,最后一個參數為函數體)
我們只要能生成函數體就可以了。生成那個函數體functionContent,以字符串形式呈現,需要我們根據template string的狀態,是code block,還是string,還是變量variable,往functionContent添加不同的語句,最后構成函數func,調用func(model)就返回了我們函數體中的result。在kino.razor中用SegmentHelper.parse將templateString轉化為一個一個segmrnt,
這個segment就是以狀態區分的內容,content 即內容,type 即類型,狀態
用ContentHelper將這個segment數組,轉變成functionContent,進而返回一個參數為model的func。
That‘s all。
3.RazorJs.js
搞清楚那個庫的原理,和流程,自己寫一個也就不是太難,模仿照着做就行。我自己搗鼓着做了一個RazorJs,將能簡化的簡化,我不想要的功能就沒做,例如kino.razor中@variable是可行的,即不加小括號'()'也可以,我就覺得不直觀,就沒有實現。在這個RazorJs中引用變量必須要用小括號括起來,如@(variable),添加了一些和jquery相關的方法,當然在沒有jquery的情況下也是可以使用razor.render 和 compile方法。修改model為ViewBag。第一遍源碼跟kino.razor太像,而且寫完第二天,發現支持的while循環沒有意義,不支持在while內部寫code block例如while(i>0) i--;這個i--沒地寫,故重新整理思路,重新寫了份,原來的更名RazorJs.0.1.js。
添加類似angularJS的ng-repeat的直接使用div作為模板的方法
例如直接在div中寫
<div razor-template razor-for="var i = 0;i<10; i++">
other template ....
</div>
使用$(selector).renderNode(ViewBag)來使render,並show出來,寫上了razor-template在dom ready的時候會被隱藏
另外一種
<div razor-repeat="item in items" razor-template>
<div>@item.age</div>
</div>
這種跟C#里面寫的foreach(var item in items)是一致的,這種div使用$(selector).renderRepeat(ViewBag),來使模板變為字符串
還有更多的擴展用法可以看csdn code 地址https://code.csdn.net/magicdawn/razorjs。那些markdown正在慢慢的寫。源碼注釋超級多,別見怪。
4.關於渲染速度...
在上面我們知道,這些其實是編譯成了一個函數 , 所以在那些測試中所謂的千次萬次render是沒有意義的,真正的次數多的render,可以先compile出來func函數,再自己調用func(ViewBag),而生成這個函數的速度,都是線性掃描,不見得能快到哪里去,所以不用擔心這個。