狄烁STEC的试验场

hello earth

导航

javascript 高级模板类

打算重写一个模板类,先学习一下John Resig大师是怎么写的

// http://ejohn.org/blog/javascript-micro-templating/
//
Simple JavaScript Templating
//
John Resig - http://ejohn.org/ - MIT Licensed
(function(){
var cache = {};

this.tmpl = function tmpl(str, data){
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = !/\W/.test(str) ?
cache[str]
= cache[str] ||
tmpl(document.getElementById(str).innerHTML) :

// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +

// Introduce the data as local variables using with(){}
"with(obj){p.push('" +

// Convert the template into pure JavaScript
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('');");

// Provide some basic currying to the user
return data ? fn( data ) : fn;
};
})();

为了便于一步一步分析,我仿照着重写了一遍,并且加上了注释:

(function(){
// 模板缓存, 键是 id, 值是已生成的模板函数
var cache = {};

// 定义 window.tmpl
this.tmpl = function tmpl(str, data){
var fn;

// 如果 str 中不存在"非单词字符"
if ( ! /\W/.test(str)){
// 即 str 是 id
if ( ! cache[str]){
// 如果在缓存里找不到该模板,就调用自身生成模板函数,并放入缓存
cache[str] = tmpl(document.getElementById(str).innerHTML);
}

fn
= cache[str];
}
else {
// str 是模板内容,包含字符串部分和脚本部分,需要转换成纯js

str
= str.replace(/[\r\t\n]/g, ' '); // 替换 换行/回车/制表符 为 空格
str = str.split('<%').join('\t'); // 替换全部 <% 为 \t
str = str.replace(/((^|%>)[^\t]*)'/g, '$1\r'); // 临时模板中非脚本部分内的 ' 为 \r
str = str.replace(/\t=(.*?)%>/g, "',$1,'"); // 分离 变量字符串
str = str.split('\t').join("');"); // 分隔模板中的字符串部分和脚本部分
str = str.split('%>').join("p.push('"); // 同上
str = str.split('\r').join("\\'"); // 还原模板中字符串部分的单引号 '

var func = "var p=[];"+
"var print=function(){"+ // print 函数没有用到
"p.push.apply(p,arguments);"+
"};" +
"with(obj){"+
"p.push('"+str+"')"+
"}"+
"return p.join('');";

// 生成解析函数
fn = new Function('obj', func);
}

return data ? fn( data ) : fn;
};
})();

这个模板类的使用方法相当灵活,模板全面支持 javascript 语法,if、for、while等等,因为它将模板字符串解析成了纯 javascript 函数。

posted on 2011-04-13 16:18  狄烁STEC  阅读(468)  评论(0编辑  收藏  举报