本版本主要是对原模板系统进行提速,去掉消耗巨大的辅助函数。本来想用它与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(报错)
<!doctype html> <html> <head> <meta charset="utf-8"/> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <meta name="keywords" content="javascript模板 by 司徒正美" /> <meta name="description" content="javascript模板 by 司徒正美" /> <title>javascript模板 by 司徒正美</title> </head> <body> <h1>John Resig的 Micro-Templating</h1> <script id="tmpl" type="text/html"> <h2><%= name %><%= name %></h2> <ul> <% for(var i=0; i< supplies.length; i++){ %> <li><%= supplies[i] %>的名字是<%= name %></li> <% } %> </ul> <% var color = "color:red;" %> <p style="text-indent:2em;<%= color %> "><%= address %></p> </script> <div id="results"></div> <script> (function(){ var cache = {}; this.tmpl = function tmpl(str, data){ var fn = !/\W/.test(str) ? cache[str] = cache[str] || tmpl(document.getElementById(str).innerHTML) : 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('');"); return data ? fn( data ) : fn; }; })(); window.onload = function(){ var els = []; for(var i=0;i<1000;i++){ els.push("第"+i+"个元素") } var a = new Date; var results = document.getElementById("results"); results.innerHTML = tmpl("tmpl", { name:"司徒正美", supplies:els, address:"异次元"}); alert( new Date-a) } </script> </body> </html>运行代码
第一个版本:
<!doctype html> <html> <head> <meta charset="utf-8"/> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <meta name="keywords" content="javascript模板 by 司徒正美" /> <meta name="description" content="javascript模板 by 司徒正美" /> <title>javascript模板 by 司徒正美</title> </head> <body> <h1>javascript模板ejs v1 by 司徒正美</h1> <script id="tmpl" type="text/html"> <h2><%= name %><%= name %></h2> <%# 这是注释!!!!!!!!! %> <ul> <% for(var i=0; i< supplies.length; i++){ %> <li><%= supplies[i] %></li> <% } %> </ul> <% var color = "color:red;" %> <p style="text-indent:2em;<%= color %>"><%= address %></p> </script> <script> (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", outerScan = function(str,buff,left,right){ var index = str.indexOf(left); if(index !== -1){ buff.push(startOfHTML, dom.quote(str.slice(0,index)), endOfHTML); innerScan(str.slice(index+2),buff,left,right); }else{ buff.push(startOfHTML, dom.quote(str), endOfHTML); } }, innerScan = function(str,buff,left,right){ var index = str.indexOf(right); if(index !== -1){ var text = str.slice(0,index); switch (text.charAt(0)) { case "#"://处理注释 break; case "="://处理后台返回的变量(输出到页面的) buff.push(startOfHTML, text.slice(1), endOfHTML) break; default: buff.push(text, "\n") } outerScan( str.slice(index+2),buff,left,right); }else{ throw "找不到右界定符 " + str } } //onsite,可选,Boolean,是否就地替换掉模板容器,默认true,如果为false,则返回一个文档碎片,交由用户自己插入到需要的地方 dom.ejs = function (obj) { var onsite = obj.onsite === void 0 , left = obj.left || "<%", right = obj.right || "%>", selector = obj.selector, buff = ["var __views = [];\n"], fragment = document.createDocumentFragment(), el = document.getElementById(selector), ejs = dom.ejs; if (!el) throw "找不到目标元素"; if(!ejs[selector]){ outerScan(el.text.trim(),buff,left,right); 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; })(); window.onload = function(){ var els = []; for(var i=0;i<1000;i++){ els.push("第"+i+"个元素") } var a = new Date dom.ejs({ selector:"tmpl", json: { name:"司徒正美", supplies:els, address:"异次元"} }); alert( new Date-a) } </script> </body> </html>运行代码
第二个版本:
<!doctype html> <html> <head> <meta charset="utf-8"/> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <meta name="keywords" content="javascript模板 by 司徒正美" /> <meta name="description" content="javascript模板 by 司徒正美" /> <title>javascript模板 by 司徒正美</title> </head> <body> <h1>javascript模板ejs v2 by 司徒正美</h1> <script id="tmpl" type="text/html"> <h2><%= name %><%= name %></h2> <%# 这是注释!!!!!!!!! %> <ul> <% for(var i=0; i< supplies.length; i++){ %> <li><%= supplies[i] %>的名字是<%= name %></li> <% } %> </ul> <% var color = "color:red;" %> <p style="text-indent:2em;<%= color %> "><%= address %></p> </script> <script> (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; })(); window.onload = function(){ var els = []; for(var i=0;i<1000;i++){ els.push("第"+i+"个元素") } var a = new Date dom.ejs({ selector:"tmpl", json: { name:"司徒正美", supplies:els, address:"异次元"} }); alert( new Date-a) } </script> </body> </html>运行代码
下一版本计划将加入局部模板与helper方法。