js模板引擎v5


上次的js模板引擎v4基本已經可以滿足大部分需求了,期間也碰到過一些問題,當模板里需要一些函數來處理數據時,必須得定一個全局函數,或者在一個全局變量上掛着一個屬性,這種用法還是感覺蠻不爽的,

沒必要為了一個只在模板內部使用的工具函數影響其外部的代碼,所以這次模板引入了像smarty模板那樣可以定義在模版內部定義函數的helper機制,同時改善了v4中所以模板數據前面必須得加個data,

比如有個對象a,模板里引用時必須得寫上data.a這樣不爽的東西,采用$a代替data.a用着的感覺好多了。

該模板優點:

1.模板采用js語法,沒有學習成本

2.也是由於優點1所以該模板的解析速度還是很占優勢的

3.可以自定義模板分隔符,就算是與js語法沖突的{{ }}都沒有問題,避免了和后端模板分隔符沖突的風險

4.引入helper機制,避免影響全局變量

//helper機制的使用
  var tpl = Template(options, helper);
 
options是一個對象,有以下屬性
  tpl 必選 待解析的模版字符串
 left 可選 左分隔符 默認 {{
 right 可選 右分隔符 默認}}
data 可選 要渲染的數據  如果在這個地方不傳入的話  可以在調用tpl.render時傳入
 
helper是一個對象,里邊必須為函數
比如
         {
            title: function(){
                return "<p>這是使用視圖helper輸出的代碼片斷</p>"
            },
            handle:function(data){
              return data.name.replace("aaa","bbb");
            }
        }
 
以下是該模板引擎核心代碼
注:變量名還是不用$換成@,避免干掉jquery的$
(function(w){
          var quote=function (str) {
                        str = str.replace(/[\x00-\x1f\\]/g, function (chr) {
                            var special = metaObject[chr];
                            return special ? special : '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4)
                        });
                        return str.replace(/"/g, '\\"') ;
                },
                metaObject = {
                    '\b': '\\b',
                    '\t': '\\t',
                    '\n': '\\n',
                    '\f': '\\f',
                    '\r': '\\r',
                    '\\': '\\\\'
                };

	w.Template=Template||{};
    function Template(options,helper){
        return this instanceof arguments.callee?this.init(options,helper):new arguments.callee(options,helper);
    }
    Template.parse=function(self){
           var temp;
           if(self.right=="}}"){//這里主要是為了解決{{{造成的bug!
              temp=self.tpl.replace(/(}})([^}])/g,function(){
                 return arguments[1]+" "+arguments[2];
              }).split(new RegExp('(?='+self.left+')|('+self.right+')(?:[^}])'))
           }else{
              temp=self.tpl.split(new RegExp('(?='+self.left+')|('+self.right+')'))
           }
            temp.filter(function(k,v){
                   return !(new RegExp(self.right)).test(v);
            }).each(
              function(k,v){
                if((new RegExp('^'+self.left)).test(v)){
				    v=v.replace('@','data.');
                    if(new RegExp('^'+self.left+'\s*=').test(v)){
                       self.body.push(v.replace(new RegExp('^'+self.left+'\s*=(.*)'),'\ttemp.push($1);\n').replace(/\\n/g,''));
                    }else{
                       self.body.push(v.replace(new RegExp('^'+self.left+'\s*(.*)'),'$1\n').replace(/\\n/g,''));
                    }
                }
                else {self.body.push('\ttemp.push(\"'+v.replace(/\n|\t/g,'')+'\");\n');}
              })
              return self.body.join("");
        };
    Template.prototype={
        init:function(options,helper){
            this.tpl=quote(options.tpl);
            this.left=options.left||"{{";
            this.right=options.right||"}}";
            this.body=[];
            this.compiled=null;
            this.data=options.data;
			this.helper=helper;
        },
        compile:function(){
            if(!this.compiled){
			    var helper=[]
			    if(this.helper){
				   for(var h in this.helper){
					 helper.push('var '+h+'='this.helper["'+h+'"]'); //helper.push('var '+h+'='+this.helper[h])
} } 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.compile()(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; }

下面是示例代碼

<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>

 

下面是輸出結果

 

這是使用視圖helper輸出的代碼片斷

隱形殺手 29
索拉 22
fesyo 23
戀妖壺 18
竜崎 25
你不懂的 30
                                                                                                                                             
 
 
 注:改變helper實現機制,上邊代碼helper函數都放到new Function了,這樣當helper函數很大時對性能影響很大,所以將其提出來了,
 
采用helpers.push('var '+h+'=this.helper["'+h+'"]');這種方式,然后調用render時傳入this,return this.compile().call(this,data||this.data);
 
最后生成的匿名函數為
 
View Code
function anonymous(data) {
    var title = this.helper.title;
    var handle = this.helper.handle;
    var temp = [];
    temp.push("\n     <div>\n\t ");
    temp.push(title());
    temp.push("\n\t \n\t ");
    temp.push(handle(data.a));
    temp.push("\n<h2>\u5BF9\u8C61\u904D\u5386</h2>\n      ");
    for (var i in data.a) {
        temp.push("\n         <li>");
        temp.push(i);
        temp.push(":");
        temp.push(data.a[i]);
        temp.push("</li>\n      ");
    }
    temp.push("\n\n\t  ");
    if (data.b == 100) {
        temp.push("\n\t     b\u7684\u503C\u4E3A:");
        temp.push(data.b);
        temp.push("\n\t  ");
    } else {
        temp.push("\n\t     b\u7684\u503C\u4E0D\u6EE1\u8DB3if\u6761\u4EF6\n\t  ");
    }
    temp.push("\n\n\t  <table style=\"text-align:center;\" >\n\t   <tr><th width='200;'>\u6B4C\u66F2\u540D</th><th width='200;'>\u6B4C\u624B</th><th width='200'>\u8FDB\u5165\u8BD5\u542C</th></tr>\n\t   ");
    for (var i = 0, l = data.song.length; i < l; i++) {
        temp.push("\n\t   <tr><td>");
        temp.push(data.song[i].songname);
        temp.push("</td><td>");
        temp.push(data.song[i].singer);
        temp.push("</td><td><a href='");
        temp.push(data.song[i].url);
        temp.push("' >");
        temp.push(data.song[i].url);
        temp.push("</a></td></tr>\n\t   ");
    }
    temp.push("\n\t  </table>\n\n       ");
    for (var i = 0, l = data.url.length; i < l; i++) {
        temp.push("\n\t         <img src='");
        temp.push(data.url[i]);
        temp.push("'/><br/>\n       ");
    }
    temp.push("\n   </div>\n");
    return temp.join("");
}

 

之前生成的匿名函數為

View Code
function anonymous(data) {
    var title = function () {return "<p>\u8FD9\u662F\u4F7F\u7528\u89C6\u56FEhelper\u8F93\u51FA\u7684\u4EE3\u7801\u7247\u65AD</p>";};
    var handle = function (data) {return data.name + "@cnblogs!";};
    var temp = [];
    temp.push("\n     <div>\n\t ");
    temp.push(title());
    temp.push("\n\t \n\t ");
    temp.push(handle(data.a));
    temp.push("\n<h2>\u5BF9\u8C61\u904D\u5386</h2>\n      ");
    for (var i in data.a) {
        temp.push("\n         <li>");
        temp.push(i);
        temp.push(":");
        temp.push(data.a[i]);
        temp.push("</li>\n      ");
    }
    temp.push("\n\n\t  ");
    if (data.b == 100) {
        temp.push("\n\t     b\u7684\u503C\u4E3A:");
        temp.push(data.b);
        temp.push("\n\t  ");
    } else {
        temp.push("\n\t     b\u7684\u503C\u4E0D\u6EE1\u8DB3if\u6761\u4EF6\n\t  ");
    }
    temp.push("\n\n\t  <table style=\"text-align:center;\" >\n\t   <tr><th width='200;'>\u6B4C\u66F2\u540D</th><th width='200;'>\u6B4C\u624B</th><th width='200'>\u8FDB\u5165\u8BD5\u542C</th></tr>\n\t   ");
    for (var i = 0, l = data.song.length; i < l; i++) {
        temp.push("\n\t   <tr><td>");
        temp.push(data.song[i].songname);
        temp.push("</td><td>");
        temp.push(data.song[i].singer);
        temp.push("</td><td><a href='");
        temp.push(data.song[i].url);
        temp.push("' >");
        temp.push(data.song[i].url);
        temp.push("</a></td></tr>\n\t   ");
    }
    temp.push("\n\t  </table>\n\n       ");
    for (var i = 0, l = data.url.length; i < l; i++) {
        temp.push("\n\t         <img src='");
        temp.push(data.url[i]);
        temp.push("'/><br/>\n       ");
    }
    temp.push("\n   </div>\n");
    return temp.join("");
}

可以看出當helper的函數較龐大時生成的這個匿名函數是多么恐怖,而且helper里的函數本來就是定義好的,干嘛不直接調用呢,還用new Function再次動態生成

 
 
js模板引擎v4版本http://www.cnblogs.com/hust/archive/2011/04/28/2032265.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM