前言
看到模板引擎,想到的就是字符串处理,正则匹配,下面正式开始处理字符串。
1. 简写版模板引擎
var str = "Hello, <%name%>"; var data = {name: 'ember'}; var result = str.replace(/<%([^%>]+)?%>/g, function(s0, s1){ return data[s1]; });
结果很理想,就是hello,ember 。当然我们写代码不可能需要这么简单的模板引擎。肯定是更复杂的需求。
var data = { name: "ember", userInfo: {age: 23} };
这时候你就想打人了,对象中嵌套对象。不要慌,总有解决办法的。。。。
2. 嵌套对象版
var str = 'Hello, <%name%>,我<%info.age%>岁啦'; var data = { name: 'ember', info: {age: 23} }; var result = str.replace(/<%([^%>]+)?%>/g, function(){ var key = arguments[1]; return "' +data." + key + "+ '"; }); result = "return '" + result + "'"; var newFn = new Function(result).apply(data);
首先我们先需要把字符串变成这个样子 'Hello, ' + data.name+ ',我' + data.info.age+ '岁啦'
用arguments[1] 获取正则匹配成功的结果,然后把这些结果返回出去
然后需要把这些字符串连接起来
最后一步很关键,构造一个新的函数,这样就可以执行我们的字符串中的js逻辑代码了!!!
var newFn = new Function(result).apply(data);
new Function 后的apply(data)主要是为了绑定构建函数时, result的作用域,防止出现错误。。。或者写成下面的格式也可以
var newFn = new Function('data',result);
但是执行函数时,必须在newFn(data),里加上data。
封装一下,毕竟我们是精致的宝宝^_^
var str = 'Hello, <%name%>,我<%info.age%>岁啦'; var data = { name: 'ember', info: {age: 23} }; var template = function(str,data) { var result = str.replace(/<%([^%>]+)?%>/g, function(){ var key = arguments[1]; return "' +data." + key + "+ '"; }); result = "return '" + result + "'"; return new Function(result).apply(data); }
template(str,data);
3. 高级版,可以解决模板引擎中嵌入js语句
var str = ` Hello, <%name%>,我<%info.age%>岁啦. <%if(data.info.age == 23){%> 我是真的23了。 <%}%>`
字符串中的js逻辑代码是要单独拿出来,不能放在字符串中,不然没办法执行。
最终代码如下:
var tplEngine = function (tpl, data) { var reg = /<%([^%>]+)?%>/g, regOut = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n', cursor = 0;
// var add = function (line, js) { js ? (code += line.match(regOut) ? line + '\n' : 'r.push(' + line + ');\n') : (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : ''); return add; }
//切分字符串 while (match = reg.exec(tpl)) { add(tpl.slice(cursor, match.index))(match[1], true); cursor = match.index + match[0].length; } add(tpl.substr(cursor, tpl.length - cursor)); code += 'return r.join("");'; console.log(code) return new Function(code.replace(/[\r\t\n]/g, '')).apply(data); };