Javascript微模板引擎,好吧,叫得这么好听其实就一简陋的前端模板。
后端模板大家应该听得比较多吧(Smarty,Velocity等),而前端我们通常是直接在JS里拼接我们需要的html,这种混合写在一起的方式,导致html结构稍微复杂点就很难看清楚,对维护造成一定的不便。所以人们就“发明”了模板这东西,使用一些特殊标记来代表数据循环、值替换等功能,使内容格式尽可能清晰。
模板的核心就是模板解析,下面要展示的引擎也仅有这个功能,没有其它扩展,要求不高的可以拿去试试!!下面我们来看一下该引擎的程序:
// Javascript Micro Templating // pzling - http://pzling.com/ var JSMT = JSMT || {}; (function(JSMT){ var tmplCaches = {}, dictDecode = { "quot": '"', "lt": "<", "gt": ">", "amp": "&", "nbsp": " " }; dictEncode = { '"': "quot", "<": "lt", ">": "gt", "&": "amp", " ": "nbsp" }; /** * HTML解码 * @param {String} html */ function htmlDecode(html) { return String(html).replace(/&(quot|lt|gt|amp|nbsp);/ig, function(all, key) { return dictDecode[key]; }); } /** * HTML编码 * @param {String} html */ function htmlEncode(html) { return String(html).replace(/["<>& ]/g, function(all) { return "&" + dictEncode[all] + ";"; }); } /** * 模板解析函数 * @param {String} templating 模板字符 */ function analyze(templating){ var _temp =templating.replace(/<#([\s\S]*?)#>/g,function(s){ return s.replace(/(\'|\\)/g,'\\$1') .replace(/[\r\n]/g,' ') .replace('<#',"_s.push('") .replace('#>',"');") .replace(/{\$([\s\S]*?)\$}/g,'\',$1,\''); }); return new Function('var _s=[];' + _temp + ';return _s'); } /** * 模板注册函数 * @param {String} id 模板字符 * @param {String} data 模板字符 */ function register(id,data){ var tar; if(!id) return ''; if(typeof id === 'object' && id.tagName){ tar = id ; id = tar.getAttribute('id'); }else{ tar = document.getElementById(id); } if(!tmplCaches[id]){ tmplCaches[id] = analyze(tar.innerHTML); } return tmplCaches[id].apply(data).join(''); } /** * 功能主调方法 * @param {String / Object} id 字符或dom对象 * @param {ALL} json 模板主要数据,任何数据类型都可以,模板使用this获取数据 */ JSMT.render = function(id,json){ var output = register.apply(this,[id,json || '']); return output; } /** * 辅助方法 */ JSMT.htmlEncode = htmlEncode; JSMT.htmlDecode = htmlDecode; })(JSMT);
程序对外提供三个方法,render是功能的主调方法,另外是两个辅助方法,用于html的编码与解码(防XSS)。下面再来看一下模板的定义方法(我拿DEMO里的模板来讲解):
<ul id="list"> <script type="text/template" id="item_tmpl1"> for(var i = 0 ,len = this.length ; i < len ; i++){ <# <li> <p><a href='{$ this[i].name $}'>{$ this[i].name $}</a></p> {$ JSMT.render("item_tmpl2",this[i].detail) $} </li> #> } </script> </ul> <script type="text/template" id="item_tmpl2"> <# <p style="margin-left:10px;">Age:{$ this.age $}</p> <p style="margin-left:10px;">Gender:{$ JSMT.htmlDecode(this.gender) $}</p> <p style="margin-left:10px;">Hobby:{$ this.hobby$}</p> #> </script>
<# #>:要输出的(html)内容;
{$ $}:要替换的变量,必须嵌套在<# #>标记内;
this:代替你传进来的数据;
PS:{$ $}只能是变量、函数调用,三元运算。
模板内容包含在<script type=”text/template”>标签内,type=”text/template”是我自定义的,因为系统识别不出这是什么type,所以它只直接忽略掉里面的内容。这里我使用了嵌套调用,在模板可以使用任意JS语法(你要定义一个函数都可以),当然一般只用 if 作逻辑处理还有 for 作循环。
接下来是功能的调用:
<script> var container = document.getElementById('list'); container.innerHTML = JSMT.render( 'item_tmpl1', [ { name:'marry', detail:{ age : 10, gender : '<span style="color:red;">girl</span>', hobby : 'reading' } }, { name:'Joe', detail:{ age : 23, gender : '<span style="color:red;">girl</span>', hobby : 'playing' } } ] ); </script>
就这么简单,传入id(或dom)与数据(JSON或JSON数组,其实什么都行,看你模板里怎么写),返回解析后的内容。方法可多次调用,例如在数据翻页,传入不同数据调用。
使用方法就上面这些,功能简单,不过在一些小项目还是可以用用的。现在JQuery与EXT等的模板引擎也都很强大的,写这个简陋的功能也仅仅是学习一下,以后再扩展其它功能
最近一直没什么状态,这功能也是每天写不到5分钟,拖到昨天才整完。前两天才开始配了下nodeJS的环境,看了些资料,终于又觉得有些小兴奋有点状态了,这几天多抽时间学一下,也希望下周可以顺利点吧。
1 Responses to this entry
从不相信没有单元测试的东西
Drop Comments