模板引擎分为前端和后端的,前端常用的模板引擎如artTemplate,juicer渲染是在客户端完成的;后端的模板引擎如基于PHP的smarty,渲染是服务器完成的。
前两天看到一篇博客挺好的是用了不到20行代码实现一个前端的模板引擎,感觉挺有趣的,今天就来实现下
逻辑
var tplEngine = function(tpl, data) {
var re = /<%([^%>]+)?%>/g;
while (match = re.exec(tpl)) {
tpl = tpl.replace(match[0], data[match[1]]);
}
return tpl;
};
就是把<%name%>
替换成data.name
即可
测试
var template1 = 'Hello, my name is <%name%>. I\'m <%age%> years old.
';
console.log(tplEngine(template1, {
name: "Tom",
age: 29
}));
var tplEngine = function(tpl, data) {
var re = /<%([^%>]+)?%>/g;
var code = 'var r=[];\n',
cursor = 0;//辅助变量
var add = function(line, js) {//针对变量还是普通的片段分别处理
js ? code += 'r.push(' + line + ');\n' :
code += 'r.push("' + line.replace(/"/g, '\\"') + '");\n';
};
while (match = re.exec(tpl)) {
add(tpl.slice(cursor, match.index));
add("this."+match[1],true);//要替换的变量
cursor = match.index + match[0].length;
}
add(tpl.substr(cursor, tpl.length - cursor));
code += 'return r.join("");'; // <-- return the result
console.info(code);
return new Function(code.replace(/[\r\t\n]/g,'')).apply(data);
};
我们研究下new Function
构造函数
new Function ([arg1[, arg2[, ...argN]],] functionBody)
argN是传入的参数,当然可以省略
函数体是code.replace(/[\r\t\n]/g,'')
,apply将函数体的上下文环境(this)指向了data
测试
var template2 = 'Hello, my name is <%name%>. I\'m <%profile.age%> years old.
';
console.log(tplEngine(template2, {
name: "Kim",
profile: {
age: 29
}
}));
按照上面的测试
var template3 =
'My skills:' +
'<%for(var index in this.skills) {%>' +
'<%skills[index]%>' +
'<%}%>';
console.log(tplEngine(template3, {
skills: ["js", "html", "css"]
}));
报错:
Uncaught SyntaxError: Unexpected token for
打印结果r.push(for(var index in this.skills) {);
是有问题的。
var r=[];
r.push("My skills:");
r.push(for(var index in this.skills) {);
r.push("");
r.push(this.skills[index]);
r.push("");
r.push(this.});
r.push("");
return r.join("");
修改
var tplEngine = function(tpl, data) {
var re = /<%([^%>]+)?%>/g,
re2 = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g;
var code = 'var r=[];\n',
cursor = 0;
var add = function(line, js) {
js ? code += line.match(re2) ? line + '\n' : 'r.push(' + line + ');\n' :
code += 'r.push("' + line.replace(/"/g, '\\"') + '");\n';
};
while (match = re.exec(tpl)) {
add(tpl.slice(cursor, match.index));
re2.test(match[1]) ? add(match[1], true) : add("this." + match[1], true);
cursor = match.index + match[0].length;
}
add(tpl.substr(cursor, tpl.length - cursor));
code += 'return r.join("");';
console.info(code);
return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
};
我们可以打印code
看看
code+='console.log(r);\n';
["My skills:", "">", "js", "", "">", "html", "", "">", "css", "", ""]
最终的结果
var r=[];
r.push("My skills:");
for(var index in this.skills) {
r.push("");
r.push(this.skills[index]);
r.push("");
}
r.push("");
console.log(r);
return r.join("");
解析结果
My skills:<a href="#">jsa><a href="#">htmla><a href="#">cssa>
参考阅读:
- 只有20行Javascript代码!手把手教你写一个页面模板引擎