下一代Jquery模板-----JsRender(2)JsRender扩展
在下一代Jquery模板-----JsRender中提到,JsRender由Jsrender标签+Html标签组成。说道Html,就很容易想起xml,xml和html一个显著的不同点就在于:xml是可扩展标记语言,也就是说,xml可以根据你的需要自己定义标签(当让要符合良好的xml格式),这就很方便了(当然不是说html不好,试想如果大家都用自己定义的标签来展示网页结构,那不惨了)。JsRender可以不勒?可以。除了下一代Jquery模板-----JsRender说的{{:}}、{{>}}、{{for /}}、{{if /}}等之外,还可以自己定制Jsrender标签、转换器、辅助函数等。这些都使JsRender具有良好的扩展性。
问题纠正
在下一代Jquery模板-----JsRender中,说道#parent关键字的时候,我说是#perent返回的是一个JsRender对象,这样说是不准确的。其实#parent返回的是当前视图#view,通过#view.data可以访问当前视图的上下文数据---#data。
<li><b>{{:#view.data.name}}</b>({{:#data.releaseYear}})</li>//{{:#view.data.XXX}}就相当于{{:#data.XXX}}
自定义JsRender标签
在Jsrender中,提供了很多进行数据绑定、逻辑处理等的标签,如{{for /}}、{{if /}}等等,但是当面临复杂的逻辑处理时候(当然我们不可能把复杂的逻辑处理放在客户端,那么系统的扩展性就不是很理想了,所以个人感觉掌握Jsrender提供的标签已经够用了),我们肯定会被{{for /}}、{{if /}}弄的焦头烂额,因为这样模板本省的可见性已经降低了,或许后期维护的时候,还需要花大量的时间去阅读模板,事倍功半了。所以,Jsrender提供了自定义标签,降低逻辑和表现之间的耦合。
//使用自定义Jsrender标签:{{tagName Entity params=values}} <li>{{:Name}}({{format Languages saySomething = "The analysis of languages:" /}})</li> ///定义Jsrender自定义标签:$.views.tags({tagName:function(Entity){XXX}}) $.views.tags({ format: function (Languages) { var ret = ""; if (this.props.saySomething) { ret += this.props.saySomething; } for (var i = 0; i < Languages.length; i++) { ret += Languages[i]; if (i == Languages.length - 2) { ret += " and "; } else if (i < Languages.length - 2) { ret += " , "; } } return ret; } });
从上面的东东可以看到,JsRender自定义标签需要注意两点:
1、Jsrender自定义标签的方法:$.views.tags({tagName:function(Entity){XXX}})。自定义标签的调用:{{tagName Entity params=values}}。可以看到实体(姑且这么说哈)既是需要渲染的属性,和{{:Name}}中的Name一样。
2、实体后还可以跟参数,格式如下:ParamName = value,在$.views.tags的定义时,通过this.props.XXX获取。
试想一下,当面对比较复杂的逻辑时候,如果用自定义标签来解决,那模板的可见性是不是更高了呢?这就可以看到模板的好处。而且面临相对复杂的逻辑,当这个自定义标签在整个应用程序中使用的时候,Jsrender的重用性也进一步体现了。
JsRender转换器
表面上看,JsRender转换器可以看做是自定义JsRender的一个补充,因为除了除了语法不通之外,唯一不通之处便是:JsRender自定义标签可以指定参数,但是转换器不能。这是由他们的本质决定的。转换器主要负责数据的转换,例如将字符串全部转换为大些。。(貌似说的不清不楚的,看下面例子就懂了)等等,但是自定义标签和{{for/}}一样,是标签,所以可以指定参数。(不清不楚啊。。。看看下面例子。。。慢慢体会啊。。。。)。一般情况,我优先选择转换器,因为更轻量级些(仅限于感觉。。。。)
//转换器调用:{{converterName:XXX}} <li>{{format:#data}}</li> //转换器定义:$.views.converters({converterName:function{XXX}}) var names = ["AAA", 1, true]; $.views.converters({ format: function (name) { return name + " is a " + typeof (name); } }); var nameHtml = $("#nameTemplate").render(names); $("#nameList").html(nameHtml);
JsRender辅助函数
除了JsRender自定义标签和转换器,JsRedner还提供了辅助函数。辅助函数的定义、调用和自定义标签以及转换器都差不多,当然我也不知道为什么会有个这个东东存在。貌似这三个东东分别标志着:标签、数据转换、函数三个基本上的扩展。废话少说,先看看辅助函数的定义和调用:
//辅助函数应用:{{~FuncName(params)}} <li>{{:name}}{{if ~nextToLast()}} and {{else ~notLast()}}, {{/if}}</li> //定义:$.views.helpers({funcName:funciton(params){XXX}}) $.views.helpers({ nextToLast: function() { var view = this; return view.index === view.data.length - 2; }, notLast: function() { var view = this; return view.index !== view.data.length - 1; } });
这里需要注意的三点:1、我们可以同时定义多个自定义标签、转换器和辅助函数(如上)。2、辅助函数、转换器、自定义标签中的this,表示的是当前视图。所以需要获取数据的时候需要this.data.XXX(parent、index等等)。3、注意这里不能直接 return this。因为这个时候返回的是当前视图对象,在模板中无法直接解析,最好的处理方案是利用this.renderContent(view)返回数据上下文对象。
ok,终于是写完了。这篇博客主要想证明,JsRedner不仅渲染性能上有很大的提升,而且JsRender具备良好的扩展性。我们可以通过自定义JsRender标签、转换器、辅助函数轻松的扩展复杂的逻辑和标签。而且这里的应用都相对简单,JsRender可以处理各种复杂的逻辑,详细的还是参考官网上:https://github.com/BorisMoore/jsrender 。不足之处,继续改进。