4行代碼實現js模板引擎


在平時編碼中,經常要做拼接字符串的工作,如把json數據用HTML展示出來,以往字符串拼接與邏輯混在在一起會讓代碼晦澀不堪,加大了多人協作與維護的成本。而采用前端模板機制就能很好的解決這個問題。

 

精妙的 tmpl

 

前端模板類開源的不少,但最屬 jQuery 作者 John Resig 開發的 “javascript micro templating” 最為精妙,寥寥幾筆便實現了模板引擎核心功能。 它的介紹與使用方式請看作者博客:http://ejohn.org/blog/javascript-micro-templating/

 

麻雀雖小,五臟俱全,除了基本的數據附加外,還擁有緩存機制、邏輯支持。現在,若要我評出一個javascript 最節能的自定義函數排名,第一名是 $ 函數(document.getElementById 簡版),而第二名就是 tmpl 了。

 

當然,它並非完美,我使用過程中發現了一些問題:

 

tmpl 美中不足

 

    一、無法正確處理轉義字符,如: tmpl('<%=name%>\\<%=id%> ', {name:'糖餅', id: '1987'});它就會報錯。若正常工作,它應該輸出:糖餅\1987

 

    二、無法識別數據里的單引號

 

    三、設置變量默認值復雜,如

 

           tmpl('<%if(obj.name){%><%=name%><%}else{%>默認值<%}%> ', {name:'糖餅'});  //設置name默認為 “默認值”

tmpl 優化版本

廢話不多說,先敬上代碼:

 

 1 function tmpl(str, data) {
 2     var $ = '$' + (+ new Date)
 3         , fn = function (data) {
 4         var i, variable = [$], value = [[]];
 5         for (i in data) {
 6             variable.push(i);
 7             value.push(data[i]);
 8         }
 9         return (new Function(variable, fn.$))
10             .apply(data, value).join("");
11     };
12 
13     //將模板解析成函數
14     fn.$ = fn.$ || $ + ".push('"
15         + str.replace(/\\/g, "\\\\")
16             .replace(/'/g, "\\'")  //防止單括號錯誤
17             .replace(/[\r\t\n]/g, " ")
18             .split("[:").join("\t")
19             .replace(/((^|:])[^\t]*)'/g, "$1\r")
20             .replace(/\t=([^\?]*?):]/g, "',$1,'")
21             .replace(/\t=([^\?]*?)\?(.*?):]/g, "',this.$1||'$2','")   //  [:=data?:]  [:=data?任何內容:]
22             .split("\t").join("');")
23             .split(":]").join($ + ".push('")
24             .split("\r").join("\\'")
25         + "');return " + $;
26 
27     //如果未定義data則返回編譯好的函數,使用時直接傳入數據即可,
28     //省去每次解析成函數的時間
29     return data ? fn(data) : fn;
30 
31 };    

好吧,上面的代碼看起來超出了4行,原諒我標題黨。不過這段代碼經過壓縮后,確實只有四行^_^。下面我們就來詳細解構它。

首先看一下使用示例:

 1 //循環結構
 2 
 3 var tpl = '[: for(var k in ary){ var one=ary[k]; :]'
 4         + '<p>[:=one:]</p>'
 5         + '[: } :]';
 6 var data = {ary:[123,'abc']};
 8 var div = tmpl(tpl,data);
10 console.log(div); //</p>123</p><p>abc</p>
11 
12 
13 //變量驗證
14 
15 var tpl = '[: if(this.name!==undefined){ :]' //注意必須使用 this.name,直接使用name,如果未定義就會報錯
16 + '<p>[:=name:]</p>'
17 + '[: } :]';
18 var data = {name:'abc'};
20 var div = tmpl(tpl,data);
22 
23 //你還可以這樣方便地使用未定義的變量: 24
25 var tpl = '<p>name:[:=name?:], name:[:=name?默認值:]</p>'; 26 var data = {no:'abc'}; 27 var div = tmpl(tpl,data); 28 29 console.log(div); // <p>name:, name:默認值</p> 30 31 32 //緩存編譯結果 33 34 35 var tpl = '[: for(var k in ary){ var one=ary[k]; :]' 36 + '<p>[:=one:]</p>' 37 + '[: } :]'; 38 var data = {ary:[123,'abc']}; 40 var render = tmpl(tpl); //不傳入data,則生成緩存,多次使用緩存節約大量正則運算 42 var div = render(data); //傳入data,代入變量,解析成最終結果 43 44 console.log(div); //<p>123</p><p>abc</p>

使用方法:在 [: 與 :] 之間使用任何js代碼,並且通過 [:=data:] 方式以字符串形式輸出變量。更加詳細的使用方法/手冊,請查看:http://docs.codekart.jojoin.com/p/tool_tmpl

優化的地方:

    一. 正確處理轉義字符 \ ' 等轉義字符

    二. 修改包裹符 <% %> 為 [: :] 防止與 html標簽</>和求余運算符%產生沖突。

    三. 修改環境變量 obj 為 this

         tmpl('<%if(obj.name=="name")%>')   //舊版本

         tmpl('[: if(this.name=="name") :]')   //新版本

    四. 為變量添加默認值

         tmpl('<%if(obj.name){%><%=name%><%}else{%>默認值<%}%>')   //舊版本

         tmpl('[:=name?默認值:]')   //新版本

    五. 去掉 with 語句,大幅提升引擎性能

    六. 刪除可有可無的功能,保持精簡

    七. 增加調試模式

        //打印模板編譯中間結果:

        console(tmpl('<p>[:=name:]</p>').$); 

        //$1408707567855.push('<p>',name,'</p>');return $1408707567855

此引擎函數大致分為兩部分:

    一. 上半部分:模板函數解析執行

    二. 下半部分:正則運算生成模板函數

可以看出,引擎實現的重點主要在下半部分的一堆正則表達式,也就是“模板編譯”的過程。這里我不打算把每一個正則的功能都說清楚,那樣篇幅太大(好吧是我懶),各位看官請自行閱讀研究。

另外,此模板引擎已被集成到 Node.js web開發框架 Codekart 中。

Codekart 是一套給 Node.js 開發者使用的應用程序開發框架和工具包。 它提供一套豐富的標准庫以及簡單的接口和邏輯結構, 其目的是使開發人員更快速地進行項目開發。 使用 Codekart 可以減少代碼的編寫量, 並將你的精力投入到項目的創造性開發上。

它已經幫你出色的完成了下面這些事情:

優雅的框架思維

如果你需要一個真正的框架,而不是一個模塊/中間件/工具箱,如果你需要簡約與便捷,需要一目了然、理所當然的舒適感,那么 Codekart 將是最好的選擇。

高性能 HTTP 服務器

Codekart 處理 http 請求的性能接近原生 Node.js 代碼: http.createServer(), 原因是框架只是對此函數做了簡單的封裝,其性能的損耗僅僅只有一個 url 正則匹配運算,路由請求處理程序。

便捷的靜態文件服務器

把文件放入 static/ 目錄下,啟動Codekart,url 訪問,搞定!

web 頁面模塊化支持

實際上,這是Codekart最出色的部分!它是前后端一體化的,可以像寫配置文件一樣編寫web頁面, 框架自動完成 js、css 、tpl 文件的模塊化加載、合並、壓縮, 並在html里引用,自動完成 html 模板的解析,並且支持頁面繼承和多態,一切就是那么簡單輕松!

豐富的工具箱

Codekart 准備了一系列強大的前后端工具集合,涉及進程通信,數據緩存,文件讀取,文件上傳,數據采集與處理,流程控制,任務計划等諸多方面。

框架源碼托管在Github:https://github.com/yangjiePro/Codekart   歡迎提交新的代碼!

 


免責聲明!

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



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