Javascript:自己写模板引擎
背景
因为JS没有提供“字符串插入”和“多行字符串”特性,传统的拼凑字符串容易出错、性能不高和不容易理解代码,为了应对这些问题,很多个人和团队开发了模板引擎,现在主流的JS框架几乎都提供此类功能了。
模板引擎的实现方式有很多种,此处介绍一种简单、灵活和强大的思路,该方式借鉴了 JSP(web 服务器最终将 JSP 页面转换为了 Servlet),编译后会把模板转换为一个方法。
这个实现只是为团队介绍模板引擎的原理,具体应用还需要选择成熟的开源实现。
实现
1 <!DOCTYPE html> 2 3 <html xmlns="http://www.w3.org/1999/xhtml"> 4 <head runat="server"> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6 <title></title> 7 </head> 8 <body> 9 </body> 10 </html> 11 <script id="test-tpl" type="text/template"> 12 start 13 14 <# for(var i=0; i< items.length; i++) {#> 15 <#= items[i].name #> 16 <# } #> 17 18 end 19 </script> 20 <script type="text/javascript"> 21 var Template = function (tpl) { 22 var me = this; 23 24 me.tpl = tpl; 25 }; 26 27 Template.prototype.compile = function () { 28 var me = this; 29 30 var codes = []; 31 codes.push("var results = [];"); 32 codes.push("with(context) {"); 33 34 var frags = me.tpl.split(/(<#=.+?#>)|(<#.+?#>)/); 35 for (var i = 0; i < frags.length ; i++) { 36 var frag = frags[i]; 37 38 if (!frag) { 39 continue; 40 } 41 if (frag.indexOf("<#=") == 0) { 42 codes.push("results.push(" + frag.substring(3, frag.length - 2) + ");"); 43 } 44 else if (frag.indexOf("<#") == 0) { 45 codes.push(frag.substring(2, frag.length - 2)); 46 } 47 else { 48 codes.push("results.push('" + frag.split('\n').join('\\n') + "');"); 49 } 50 } 51 52 codes.push("}"); 53 codes.push("return results.join('');"); 54 55 console.log(codes.join("\n")); 56 me.compiledTplFun = new Function("context", codes.join("\n")); 57 }; 58 59 Template.prototype.apply = function (context) { 60 var me = this; 61 62 if (!me.compiledTplFun) { 63 me.compile(); 64 } 65 66 return me.compiledTplFun(context); 67 }; 68 69 var tpl = new Template(document.getElementById("test-tpl").innerHTML) 70 71 console.log(tpl.apply({ items: [{ name: "dgw" }] })); 72 </script>