这是2013年的某个项目, 开发自己的编辑器, 当中需要用到模板引擎, 后自己简单琢磨了下, 实现了个简易版的.
实现模板解析最大的难题就是 变量解析 , 和如何有效的拼接可执行的字符串。
例: hello world {$title} 好 {$content} {for(var i in data)} 你好 {/for} ,里面有 title,cotnent,data,及for循环, "{$ }" 代表变量, "{for}"代表循环,{/for}代表循环结束, 而我如何得到正确的结果 ?
首先我们要将这段文本转化成一段可执行的代码字符串。 而用户最终要得到的结果字符串,我们用一个变量来保存起来,我暂且先命名为returns_html.
那么我将 {$title} 替换成 " + title + " , 将 {for(var i in data)}转化为 ";for(var i in data) { returns_html += " , 将{/for} 转化为 ";} returns_html +=",最后我得到的字符串为:
hello world "+ title+" 好" +content+ "";for(var i in data) { returns_html +="你好";} returns_html +="
这段字符串想要执行还差什么, 两边还差 双引号,除了双引号外, 还缺了returns_html的定义,赋值和返回, 加上它们:
var returns_html="hello world "+ title+" 好" +content+ "";for(var i in data) { returns_html +="你好";} returns_html +="";return returns_html;
现在这个字符串就能够去远行了,可还有变量解析的问题。 用户传过来的数据肯定一个json对象, 例:{title:"title",content:"content",data:[1,2,3,4]}
我暂且将用户传过来的数据赋值给$tpldata, 可如何将$tpldata打散传给他们呢, 我看了很多人解决的方案是以对象的形式将变量名前加上$tpldata,便 {$title} 替换成 $tpldata.title, 可我不想这样做, 因为变量名很有可能出现在循环的小括号中,如(for(var i in data)) 中的data变量,你如何去识别data这 是个变量呢, 所以我通过 new function 的形式, 将模板的变量 传递 过去. 并将拼接的字符串 当作代码来执行.
new Function("title","content","data",‘ var returns_html="hello world "+ title+" 好" +content+ "";for(var i in data) { returns_html +="你好";} returns_html +=""‘) (title,content,data)
那么这个问题就解决了,
任何语言对于技术来说不如源码更有表达力, 贴出源代码:
1 (function(a){ 2 a.tpl = { 3 render:function(html,$tpldata){ 4 var arr = [ 5 {"pattern" :/\"/g,"replace":‘\\\\"‘ }, //过滤双引号 6 {"pattern" :/\\n/g,"replace":‘‘ }, // 7 {"pattern" :/{(while[^}]*)}/g,"replace":‘";$1{ returns_html +="‘ }, //while 8 {"pattern" :/{(for[^}]*)}/g,"replace":‘";$1{ returns_html +="‘ }, //for 9 {"pattern": /{(if[^}]*)}/g,"replace": ‘";$1{ returns_html +="‘}, //if 10 {"pattern": /{(else if[^}]*)}/g,"replace": ‘";$1{ returns_html +="‘}, //else if 11 {"pattern": /({\/if})|({\/for})|({\/while})}/g, "replace": ‘";} returns_html +="‘}, //结束 12 {"pattern": /{\$ ([^}}]*)}/g, "replace": ‘";$1;returns_html+="‘}, //js {$ js} 13 {"pattern": /{\$([^} ]*)}/g, "replace": ‘"+$1+"‘} //变量解析{$val} 14 ],param=[],params=[]; 15 for(var i = 0,n = arr.length;i<n;i++){ 16 html = html.replace(arr[i][‘pattern‘],arr[i][‘replace‘]); 17 } 18 html = ‘var returns_html=""; returns_html += " ‘ +html+ ‘";return returns_html;‘; 19 20 21 //变量打散 ,再套一层new Function 22 for(var i in $tpldata){ 23 if($tpldata.hasOwnProperty(i)){ 24 param.push(i); 25 params.push("$tpldata[‘"+i+"‘]"); 26 } 27 } 28 try{ 29 return new Function("$tpldata",‘return new Function("‘+param.join(‘","‘)+‘",\‘‘+html.replace(/\‘/g,"\\‘")+‘\‘)(‘+params.join(",")+‘)‘)($tpldata); 30 }catch(e){ 31 console.log(e.message); 32 console.log(html); 33 return ‘‘; 34 } 35 } 36 } 37 })(window);
你看, 代码多么easy ! 但是基本的js 语法,都大概支持, 变量,循环,判断都有了,还支持直接写入源码。 此模板引擎在大部分情况下足够用啦。