js 如何实现模板引擎

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js 如何实现模板引擎相关的知识,希望对你有一定的参考价值。

   这是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 语法,都大概支持, 变量,循环,判断都有了,还支持直接写入源码。  此模板引擎在大部分情况下足够用啦。 

 

以上是关于js 如何实现模板引擎的主要内容,如果未能解决你的问题,请参考以下文章

百度JS模板引擎

14行实现js原生语法前端模板引擎

14行实现js原生语法前端模板引擎

深入node.js 3 模板引擎原理 事件 文件操作 可读流的实现原理

JavaScript中template模板引擎

vscode代码片段生成vue模板