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),而生成这个函数的速度,都是线性扫描,不见得能快到哪里去,所以不用担心这个。