templateJS的诞生,是缘于iDocSet 6.0 要支持列印《Guides and Sample Code》文档集的API文档(这些文档是Xcode内置的,原来只有Xcode才能看的),在找到API的JSON数据后如何通过HTML页面展现出来便成了问题,这需要模板引擎帮忙了。我原来用freemarker模板引擎,但这只是Java的。起先想找到可用的ObjC的模板引擎,很少,也没合适的,又找了JavaScript的模板引擎,觉得不理想,不中用,故索性下手尝试,撸了这一个轻量级的JavaScript模板引擎,结合JavaScriptCore Framework,得以成功使用。
从原理上看,templateJS的想法及实现是非常简单的,即将模板内容转化为JavaScript代码,通过执行这些代码来输出最终结果。
一般模板引擎遵循如下操作:
模板(template) + 数据(data modal) = 结果(result)
<script type="text/template" id="test-template">
<h3><@= o.title @></h3>
<ol>
<@ for (var i = 0; i < o.features.length; i++) {
var item = o.features[i]; @>
<li><@= item.name @> <@ if (item.desc) { out += '<i>' + item.desc + '</i>'; } @></li>
<@ } @>
</ol>
<p><b><@= o.author @></b></p>
</script>
注:这个模板上面输出标题,中间通过循环输出功能列表,最后输出作者信息。在输出功能列表时又利用了out输出流,写入功能描述信息。
var data = {
title: 'templateJS: lightweight JavaScript Template Engine',
features: [
{ name: 'Build with pure JavaScript' },
{ name: 'Lightweight and Fast', desc: 'less than 600 bytes' },
{ name: 'Simple and Ease of use' }
],
author: 'zhsoft88@icloud.com'
};
注:用JavaScript对象或JSON格式来定义数据。
var source = document.getElementById('test-template').innerText;
var tmpl = new Template(source);
注:source为上面所列模板的内容,此处生成一个可重用的模板对象tmpl。
var result = tmpl.render(data);
<h3>templateJS: lightweight JavaScript Template Engine</h3>
<ol>
<li>Build with pure JavaScript </li>
<li>Lightweight and Fast <i>less than 600 bytes</i></li>
<li>Simple and Ease of use </li>
</ol>
<p><b>zhsoft88@icloud.com</b></p>
1. <@= JavaScript表达式 @>
通过此种方式,引用JavaScript表达式产生的值
2. <@ 任意JavaScript代码 @>
在<@和@>之间可写入执行任意JavaScript代码
3. o
使用o来引用传给模板的数据对象
4. out
out为输出流,使用out可给模板结果增加输出
5. 模板内容的引用
简单的话,可通过字符串方式引用,如下:
var tmpl = new Template('<h3><@= o.title @></h3>...');
这种方式的缺点是,如果字符串里头有换行、单引号、反斜杠等字符,必须进行转义处理。
也可以用声明一个带id属性的type为text/template的script节点,在此节点内写模板内容,然后通过id得到模板内容对象,再通过innerText得到模板内容。
<script type="text/template" id="template-id">
.....
</script>
这种方式不需要转义特殊字符,缺点是需要DOM支持,只适合运行在浏览器中的HTML页面。
如果是在程序中想用templateJS,没有DOM支持,或者说不需要DOM,该怎么办?
答案是利用JavaScriptCore Framework,给JSContext对象绑定一个helper对象,利用helper对象给JavaScript提供得到模板内容的方法,如:
1) 声明一个protocol,注意得继承JSExport
@protocol ZHTHelperExport <JSExport>
- (NSString*)getTemplateSourceById:(NSString*)id;
@end
2) 写一个类,如ZHTHelperImpl,去实现ZHTHelperExport协议,即实现通过id得到模板内容的方法。
@interface ZHTHelperImpl : NSObject<ZHTHelperExport>
@end
@implementation ZHTHelperImpl
- (NSString*) getTemplateSourceById:(NSString*)id {
...
}
@end
3) 绑定helper对象
JSContext* context = ...;
context[@"helper"] = [ZHTHelperImpl new];
[context evaluateScript:@"var source = helper.getTemplateSourceById('test-template');"];
测试页面 - test-templateJS.html
GitHub地址: - https://github.com/zhsoft88/templateJS