js模版引擎v6注解

下面是小C的js模版引擎v6,写得非常精巧。

先看一下怎么使用吧。

 var tpl = Template(options, helper).render();

  html模版,分隔符分别是<&和&>,@会被解析为"data.",就是你的数据对象,避免了使用with。

  <script type="tmpl" id="table_tmpl">
        <&= title() &>
        <table border=1>
        <& for(var i=0,tl = @trs.length,tr;i<tl;i++){  &>
            <& tr = @trs[i]; &>
            <tr>
            <td><&= tr.name&></td> <td><&= tr.age&></td> <td><&= tr.sex || '男' &></td>
            </tr>
            <& } &>
        </table>
        <img src="<&= @href &>">
</script>

<script> 
    var trs = [
            {name:"隐形杀手",age:29,sex:"男"},
            {name:"索拉",age:22,sex:"男"},
            {name:"fesyo",age:23,sex:"女"},
            {name:"恋妖壶",age:18,sex:"男"},
            {name:"竜崎",age:25,sex:"男"},
            {name:"你不懂的",age:30,sex:"女"}
        ]
 
        var html = Template({
           tpl:document.getElementById("table_tmpl").text,
           left:"<&",
           right:"&>",
           data:{
            trs: trs,
            href: "http://images.cnblogs.com/cnblogs_com/rubylouvre/202906/o_type4.jpg"
          }
        },{
            title: function(){
                return "<p>这是使用视图helper输出的代码片断</p>"
           }
                   
        });
        document.getElementById("test123").innerHTML=html.render()
  </script>

下面是引擎的源代码,就让我来为你详细讲解吧

先找到入口,render方法就是整个引擎的入口

//闭包,w是window对象
(function(w){
    //定义Template对象,使其单例
    w.Template=Template||{};
    function Template(options,helper){
        //将this对象指向Template对象 ,并初始化
        return this instanceof Template?this.init(options,helper):new Template(options,helper);
    }
    Template.parse=function(self){  //引擎的核心代码
           if(!self.__lines){
             self.__lines=[];
           }
           var temp,i=0;
           //?: 不分组  ?= 紧跟者
           //按照分隔符分开,如果遇到分隔符是{{,}}的情况,{{{44}}},会先被分为"{{{44} }}",最后被分割为["{","{{44}", "}}"]
           //例如:{{}}} ->["{{}", "}}"]  {{{->["{","{{"] 
           if(self.right=="}}"){//这里是为了解决}}}造成的bug!
              temp=self.tpl.replace(/(}})([^}])/g,"$1 $2").split(new RegExp('(?='+self.left+')|('+self.right+')(?:[^}])'))
           }else{
              temp=self.tpl.split(new RegExp('(?='+self.left+')|('+self.right+')'))
           }
    
            //过滤右分隔符,["{","{{44}", "}}"] -> ["{","{{44}"]
            temp.filter(function(k,v){
                   return !(new RegExp(self.right)).test(v);
            }).each(
              function(k,v){  //核心代码
                //分3中情况
                //<&= title()   '^'+self.left+'\s*='    temp.push(title())  放到temp中
                //<& for(var i=0,tl = @trs.length,tr;i<tl;i++){  &>   直接放到self.body中
                //<table border=1>                    放到temp中
                if((new RegExp('^'+self.left)).test(v)){
                    v=v.replace(/@/g,'data.');
                    if(new RegExp('^'+self.left+'\s*=').test(v)){
                       self.body.push(v.replace(new RegExp('^'+self.left+'\s*=(.*)'),'\ttemp.push($1);\n'));
                    }else{
                       self.body.push(v.replace(new RegExp('^'+self.left+'\s*(.*)'),'$1\n'));
                    }
                }
                else {
                  //这样写就不需要转义
                  self.__lines[i]=v;
                  self.body.push('\ttemp.push(this.__lines['+(i++)+']);\n');
                }
              })
    
              //返回方法体,temp中的才是最终的html代码
              return self.body.join("");
        };
    Template.prototype={

        //初始化
        init:function(options,helper){
            this.tpl=options.tpl;   //html模版
            this.left=options.left||"{{"; //左分隔符,本例中就是<&
            this.right=options.right||"}}"; //左分隔符,本例中就是&>
            this.body=[];     //主要用来存放模版的主要方法体
            this.compiled=null;    //定义compiled方法
            this.data=options.data;   //数据
            this.helper=helper;         //helper对象
        },
        compile:function(){   //编译模版,将模版解析为一个function
            if(!this.compiled){  //已经缓存就不需要在编译
                var helper=[];
                if(this.helper){  //将helper对象解析为var <key> = <value> 的变量定义形式
                   for(var h in this.helper){
                     helper.push('var '+h+'=this.helper["'+h+'"]'); 
                   }
                }

                //将整个模版转化为一个function,此处是整个引擎的实现原理
    /**
     *  本例中的模版解析后的方法是
     *  function(data){
            //helper对象
            var title = function(){
                            return "<p>这是使用视图helper输出的代码片断</p>"
                        }
      var temp=[];
      temp.push(title());
      temp.push('<table border=1>');
      for(var i=0,tl = data.trs.length,tr;i<tl;i++){
          tr = data.trs[i];
          temp.push('<tr>\r\n<td>');
          temp.push(tr.name);
          temp.push('</td> <td>');
          temp.push(tr.age);
          temp.push('</td> <td>');
          temp.push(tr.sex || '男');
          temp.push('</td>\r\n</tr>');
      }
      return temp.join("");
        }
     *
     */
                this.compiled=new Function("data",helper.join(";")+';var temp=[];\n'+Template.parse(this)+'\n return temp.join("");');
            }
            return this.compiled;
        },
        render:function(data){
            return this.compile().call(this,data||this.data);
        }
    }
})(this);
 Array.prototype.filter=function(fn){
   var temp=[];
   for(var i=0,l=this.length;i<l;i++){
      this[i]&&fn.call(this,i,this[i])&&temp.push(this[i]);
   }
  return temp;
}
Array.prototype.each=function(fn){
   var temp=[];
   for(var i=0,l=this.length;i<l;i++){
     fn.call(this,i,this[i]);
   }
   return this;
}

 Array.prototype.filter=function(fn){
   var temp=[];
   for(var i=0,l=this.length;i<l;i++){
      this[i]&&fn.call(this,i,this[i])&&temp.push(this[i]);
   }
  return temp;
}
Array.prototype.each=function(fn){
   var temp=[];
   for(var i=0,l=this.length;i<l;i++){
     fn.call(this,i,this[i]);
   }
   return this;
}

原文地址:https://www.cnblogs.com/oceanxing/p/2669697.html