本版本主要是對原模板系統進行提速,去掉消耗巨大的輔助函數。本來想用它與John Resig的 Micro-Templating比較一下速度,發現對方無法處理複雜的模板,殘念。
//司徒正美 javascript template - http://www.cnblogs.com/rubylouvre/ - MIT Licensed (function () { if(!String.prototype.trim){ String.prototype.trim = function(str) { return this.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); } } var dom = { 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', '\\': '\\\\' }, parser = document.createElement("div"), startOfHTML = "\t__views.push(", endOfHTML = ");\n"; //onsite,可選,Boolean,是否就地替換掉模板容器,預設true,如果為false,則返回一個文檔片段,交由使用者自己插入到需要的地方 dom.ejs = function (obj) { var onsite = obj.onsite === void 0 , left = obj.left || "<%", right =obj.right || "%>", selector = obj.selector, isLeft = true, buff = ["var __views = [];\n"], fragment = document.createDocumentFragment(), el = document.getElementById(selector), ejs = dom.ejs; if (!el) throw "找不到目標元素"; var str = el.text.trim(); if(!ejs[selector]){ while(str.length){ var condition = isLeft ? left :right; var index = str.indexOf(condition); if(index !== -1){//取左邊 var text = str.slice(0,index); if(isLeft){ buff.push(startOfHTML, dom.quote(text.trim()), endOfHTML); }else{ switch (text.charAt(0)) { case "#"://處理注釋 break; case "="://處理後台返回的變數(輸出到頁面的); buff.push(startOfHTML, text.slice(1), endOfHTML) break; default: buff.push(text, "\n") }; } }else{ if(isLeft){ buff.push(startOfHTML, dom.quote(str), endOfHTML); break; }else{ throw "在字串{{ "+dom.quote(str)+" }}中找不到右界定符"+right } } str = str.slice(index+2).trim(); isLeft = !isLeft; } ejs[selector] = new Function("json", "with(json){"+buff.join("") + '};return __views.join("");') } parser.innerHTML = ejs[selector](obj.json || {}); while (parser.firstChild) { fragment.appendChild(parser.firstChild) } return onsite ? el.parentNode.replaceChild(fragment, el) : fragment; }; window.dom = dom; })();
John Resig的 Micro-Templating(報錯)
<br /><!doctype html><br /><html><br /> <head><br /> <meta charset="utf-8"/><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <meta name="keywords" content="javascript模板 by 司徒正美" /><br /> <meta name="description" content="javascript模板 by 司徒正美" /><br /> <title>javascript模板 by 司徒正美</title><br /> </head><br /> <body><br /> <h1>John Resig的 Micro-Templating</h1><br /> <script id="tmpl" type="text/html"><br /> <h2><%= name %><%= name %></h2><br /> <ul><br /> <% for(var i=0; i< supplies.length; i++){ %><br /> <li><%= supplies[i] %>的名字是<%= name %></li><br /> <% } %><br /> </ul><br /> <% var color = "color:red;" %><br /> <p style="text-indent:2em;<%= color %> "><%= address %></p><br /> </script><br /> <div id="results"></div><br /> <script></p><p> (function(){<br /> var cache = {};<br /> this.tmpl = function tmpl(str, data){<br /> var fn = !/\W/.test(str) ? cache[str] = cache[str] || tmpl(document.getElementById(str).innerHTML) :<br /> new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + "with(obj){p.push('" + str.replace(/[\r\t\n]/g, " ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g, "$1\r").replace(/\t=(.*?)%>/g, "',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'") + "');}return p.join('');");<br /> return data ? fn( data ) : fn;<br /> };<br /> })();</p><p> window.onload = function(){<br /> var els = [];<br /> for(var i=0;i<1000;i++){<br /> els.push("第"+i+"個元素")<br /> }<br /> var a = new Date;<br /> var results = document.getElementById("results");<br /> results.innerHTML = tmpl("tmpl", {<br /> name:"司徒正美",<br /> supplies:els,<br /> address:"異次元"});<br /> alert( new Date-a)<br /> }<br /> </script><br /> </body><br /></html><br />
運行代碼
第一個版本:
<br /><!doctype html><br /><html><br /> <head><br /> <meta charset="utf-8"/><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <meta name="keywords" content="javascript模板 by 司徒正美" /><br /> <meta name="description" content="javascript模板 by 司徒正美" /><br /> <title>javascript模板 by 司徒正美</title><br /> </head><br /> <body><br /> <h1>javascript模板ejs v1 by 司徒正美</h1><br /> <script id="tmpl" type="text/html"><br /> <h2><%= name %><%= name %></h2><br /> <%# 這是注釋!!!!!!!!! %><br /> <ul><br /> <% for(var i=0; i< supplies.length; i++){ %><br /> <li><%= supplies[i] %></li><br /> <% } %><br /> </ul><br /> <% var color = "color:red;" %><br /> <p style="text-indent:2em;<%= color %>"><%= address %></p><br /> </script></p><p> <script></p><p> (function () {<br /> if(!String.prototype.trim){<br /> String.prototype.trim = function(str) {<br /> return this.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');<br /> }<br /> }<br /> var dom = {<br /> quote: function (str) {<br /> str = str.replace(/[\x00-\x1f\\]/g, function (chr) {<br /> var special = metaObject[chr];<br /> return special ? special : '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4)<br /> });<br /> return '"' + str.replace(/"/g, '\\"') + '"';<br /> }<br /> },<br /> metaObject = {<br /> '\b': '\\b',<br /> '\t': '\\t',<br /> '\n': '\\n',<br /> '\f': '\\f',<br /> '\r': '\\r',<br /> '\\': '\\\\'<br /> },<br /> parser = document.createElement("div"),<br /> startOfHTML = "\t__views.push(",<br /> endOfHTML = ");\n",<br /> outerScan = function(str,buff,left,right){<br /> var index = str.indexOf(left);<br /> if(index !== -1){<br /> buff.push(startOfHTML, dom.quote(str.slice(0,index)), endOfHTML);<br /> innerScan(str.slice(index+2),buff,left,right);<br /> }else{<br /> buff.push(startOfHTML, dom.quote(str), endOfHTML);<br /> }<br /> },<br /> innerScan = function(str,buff,left,right){<br /> var index = str.indexOf(right);<br /> if(index !== -1){<br /> var text = str.slice(0,index);<br /> switch (text.charAt(0)) {<br /> case "#"://處理注釋<br /> break;<br /> case "="://處理後台返回的變數(輸出到頁面的)<br /> buff.push(startOfHTML, text.slice(1), endOfHTML)<br /> break;<br /> default:<br /> buff.push(text, "\n")<br /> }<br /> outerScan( str.slice(index+2),buff,left,right);<br /> }else{<br /> throw "找不到右界定符 " + str<br /> }<br /> }</p><p> //onsite,可選,Boolean,是否就地替換掉模板容器,預設true,如果為false,則返回一個文檔片段,交由使用者自己插入到需要的地方<br /> dom.ejs = function (obj) {<br /> var onsite = obj.onsite === void 0 ,<br /> left = obj.left || "<%",<br /> right = obj.right || "%>",<br /> selector = obj.selector,<br /> buff = ["var __views = [];\n"],<br /> fragment = document.createDocumentFragment(),<br /> el = document.getElementById(selector),<br /> ejs = dom.ejs;<br /> if (!el) throw "找不到目標元素";<br /> if(!ejs[selector]){<br /> outerScan(el.text.trim(),buff,left,right);<br /> ejs[selector] = new Function("json", "with(json){"+buff.join("") + '};return __views.join("");')<br /> }<br /> parser.innerHTML = ejs[selector](obj.json || {});<br /> while (parser.firstChild) {<br /> fragment.appendChild(parser.firstChild)<br /> }<br /> return onsite ? el.parentNode.replaceChild(fragment, el) : fragment;<br /> };<br /> window.dom = dom;</p><p> })();</p><p> window.onload = function(){<br /> var els = [];<br /> for(var i=0;i<1000;i++){<br /> els.push("第"+i+"個元素")<br /> }<br /> var a = new Date<br /> dom.ejs({<br /> selector:"tmpl",<br /> json: {<br /> name:"司徒正美",<br /> supplies:els,<br /> address:"異次元"}<br /> });<br /> alert( new Date-a)<br /> }<br /> </script><br /> </body><br /></html><br />
運行代碼
第二個版本:
<br /><!doctype html><br /><html><br /> <head><br /> <meta charset="utf-8"/><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <meta name="keywords" content="javascript模板 by 司徒正美" /><br /> <meta name="description" content="javascript模板 by 司徒正美" /><br /> <title>javascript模板 by 司徒正美</title><br /> </head><br /> <body><br /> <h1>javascript模板ejs v2 by 司徒正美</h1><br /> <script id="tmpl" type="text/html"><br /> <h2><%= name %><%= name %></h2><br /> <%# 這是注釋!!!!!!!!! %><br /> <ul><br /> <% for(var i=0; i< supplies.length; i++){ %><br /> <li><%= supplies[i] %>的名字是<%= name %></li><br /> <% } %><br /> </ul><br /> <% var color = "color:red;" %><br /> <p style="text-indent:2em;<%= color %> "><%= address %></p><br /> </script></p><p> <script></p><p> (function () {<br /> if(!String.prototype.trim){<br /> String.prototype.trim = function(str) {<br /> return this.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');<br /> }<br /> }<br /> var dom = {<br /> quote: function (str) {<br /> str = str.replace(/[\x00-\x1f\\]/g, function (chr) {<br /> var special = metaObject[chr];<br /> return special ? special : '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4)<br /> });<br /> return '"' + str.replace(/"/g, '\\"') + '"';<br /> }<br /> },<br /> metaObject = {<br /> '\b': '\\b',<br /> '\t': '\\t',<br /> '\n': '\\n',<br /> '\f': '\\f',<br /> '\r': '\\r',<br /> '\\': '\\\\'<br /> },<br /> parser = document.createElement("div"),<br /> startOfHTML = "\t__views.push(",<br /> endOfHTML = ");\n";</p><p> //onsite,可選,Boolean,是否就地替換掉模板容器,預設true,如果為false,則返回一個文檔片段,交由使用者自己插入到需要的地方<br /> dom.ejs = function (obj) {<br /> var onsite = obj.onsite === void 0 ,<br /> left = obj.left || "<%",<br /> right =obj.right || "%>",<br /> selector = obj.selector,<br /> isLeft = true,<br /> buff = ["var __views = [];\n"],<br /> fragment = document.createDocumentFragment(),<br /> el = document.getElementById(selector),<br /> ejs = dom.ejs;<br /> if (!el) throw "找不到目標元素";<br /> var str = el.text.trim();<br /> if(!ejs[selector]){<br /> while(str.length){<br /> var condition = isLeft ? left :right;<br /> var index = str.indexOf(condition);<br /> if(index !== -1){//取左邊<br /> var text = str.slice(0,index);<br /> if(isLeft){<br /> buff.push(startOfHTML, dom.quote(text.trim()), endOfHTML);<br /> }else{<br /> switch (text.charAt(0)) {<br /> case "#"://處理注釋<br /> break;<br /> case "="://處理後台返回的變數(輸出到頁面的);<br /> buff.push(startOfHTML, text.slice(1), endOfHTML)<br /> break;<br /> default:<br /> buff.push(text, "\n")<br /> };<br /> }<br /> }else{<br /> if(isLeft){<br /> buff.push(startOfHTML, dom.quote(str), endOfHTML);<br /> break;<br /> }else{<br /> throw "在字串{{ "+dom.quote(str)+" }}中找不到右界定符"+right<br /> }<br /> }<br /> str = str.slice(index+2).trim();<br /> isLeft = !isLeft;<br /> }<br /> ejs[selector] = new Function("json", "with(json){"+buff.join("") + '};return __views.join("");')<br /> }<br /> parser.innerHTML = ejs[selector](obj.json || {});<br /> while (parser.firstChild) {<br /> fragment.appendChild(parser.firstChild)<br /> }<br /> return onsite ? el.parentNode.replaceChild(fragment, el) : fragment;<br /> };<br /> window.dom = dom;</p><p> })();</p><p> window.onload = function(){<br /> var els = [];<br /> for(var i=0;i<1000;i++){<br /> els.push("第"+i+"個元素")<br /> }<br /> var a = new Date<br /> dom.ejs({<br /> selector:"tmpl",<br /> json: {<br /> name:"司徒正美",<br /> supplies:els,<br /> address:"異次元"}<br /> });<br /> alert( new Date-a)<br /> }<br /> </script><br /> </body><br /></html><br />
運行代碼
下一版本計劃將加入局部模板與helper方法。