您的位置:首页 > Web前端 > JavaScript

JavaScript模板引擎的改进

2012-09-29 11:47 417 查看
阅读本文章之前,请先阅读 两个灵活高效的javascript模板渲染函数 ,因为这是针对那个模板引擎的改进。

那个模板引擎实现原理里,在每次渲染数据之前,会先把html模板编译成一个js函数,然后遍历每条数据调用这个函数,就完成整个数据列表的渲染。

改进的思路是:把html模板“编译”一次之后,就缓存起来,下次再渲染这个模板的时候,直接使用编译过的函数,而不用再次编译模板。

改进的方案之一

原理:用数组存放模板,即把html模板字符串封装进一个数组里,这个数组只有这个字符串元素。每次调用模板引擎的时候,模板引擎编译完html之后,会把编译后的函数替换这个数组里模板字符串。这样当再次调用模板引擎的时候,先判断这个模板数组里存放的是字符串还是函数,是字符串就编译模板,是函数就不用再次编译。

改进后的模板格式:

//改进前的模板,就是一个字符串
var tpl = '<li>' +
'<div class="headPic"><a href="{domain}" title="{name}"><span></span></a>' +
'<img alt="" src="{head}" width="60" height="60"/>' +
'</div>' +
'<div class="feedCon">' +
'<span>{$.abx?[这是奇数行]+$.name:[偶的]}</span>' +
'<span>{ $.abc===5 ? [是5] : [是]+$.abc }</span>' +
'</div>' +
'</li>';
//改进后的模板,包了个数组外壳
var tpl = ['<li>' +
'<div class="headPic"><a href="{domain}" title="{name}"><span></span></a>' +
'<img alt="" src="{head}" width="60" height="60"/>' +
'</div>' +
'<div class="feedCon">' +
'<span>{$.abx?[这是奇数行]+$.name:[偶的]}</span>' +
'<span>{ $.abc===5 ? [是5] : [是]+$.abc }</span>' +
'</div>' +
'</li>'];
为什么要从字符串换成数组,这是因为用字符串去调用一个函数的时候,是传值调用,函数里无法改变原字符串的值,而用数组这种非基本类型的对象去调用函数,相当于传址调用,在函数里可以改变原数组的内容。这样才能把模板字符串调包成“编译”后的函数。

改进后的模板引擎:

N.template = function(tpl, arrData, mix){
if( !arrData || !arrData.length ){
return '';
}
var ret = '',
hasMix = typeof mix==='function',
i, len,
evaluate,
datai, mixdata, k;

if( typeof tpl[0] === 'function' ){
evaluate = tpl[0];
}else{
var tpls = tpl[0].replace(/[\r\n\t]/g,'').replace(/\'/g,"\\\'").split('{'),
sous,
source = "return '"+tpls[0]+"'";

for(i = 1, len = tpls.length; i<len; i++){
sous = tpls[i].split('}');
source = source +(sous[0].indexOf('$')===-1?"+$."+sous[0]:
"+("+sous[0].replace(/\[|\]/g,"'")+")")+"+'"+sous[1]+"'";
}
console.log(source); //只会输出一次
evaluate = tpl[0] = new Function('$', source);
}

for(i = 0, len = arrData.length; i<len; i++){
datai = arrData[i];

if(hasMix){
mixdata = mix(datai, i);
for(k in mixdata){
datai[k] = mixdata[k];
}
}

ret += evaluate(datai);
}
console.log('ret now...'); //每次都会输出
return ret;
};
改进后的调用方式不变:

var datas = [
{domain:'domainshit', name:'FLM', head:'headdffdddd',ab:3},
{domain:'dodshit', name:'FLMMjj', head:'he788ddd',ab:2},
{domain:'dode3errrrrtshit', name:'FL4MMjj', head:'he78y70008ddd',ab:5},
{domain:'dors2dshit', name:'FL3MMjj', head:'he78811ddd',ab:2},
{domain:'doma', name:'FffLM', head:'he2addd',ab:3}
];

N.template(tpl, datas, function(d,i){
return {
abx: i&1,
abc: d.ab+2
};
});
N.template(tpl, datas, function(d,i){
return {
abx: i&1,
abc: d.ab+2
};
});
改进后,可以发现用同一个html模板多次渲染数据,只会编译一次模板。

改进的方案之二

思路:把模板引擎写成一个类,用html模板字符串和混合函数初始化这个类,初始化类的时候把模板字符串编译成函数。这个类提供两个prototype方法:一个是重置混合函数的方法(估计用到的几率十分十分小),一个是渲染数据到模板的方法。

渲染模板的时候,就先初始化一个实例,这样渲染不同数据的时候,只用这个实例就行,而只有初始化这个实例的时候编译过一次模板,达到了我们的改进目的。

这个方案的具体代码自己写吧。

小结:我原本以为之前那篇博文里的模板引擎已是很好,没有可改进的地方,但随着见识的增长,总是会让你发现很多可以改进的点。如果想变得越来越专业,只有谦虚好学,多思考。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: