国庆节过去第一天,有点懒,但一想到今年的法定节假日都已经过完,慢慢就燃起奋斗欲望。今天碰巧看到网络上一些高手博客写着渲染模板教程,就做个随笔记录吧!
渲染模板简单的说,就是将一些数据,字符串加载到几个的变量当中。
var tpl = 'Hei, my name is <%name%>, and I\'m <%age%> years old.';
js数据加载方式
var data = {
"name": "Barret Lee",
"age": "20"
};
var result = tplEngine(tpl, data);
所以我们就上面代码,做个js编译,我们要把<%name%>识别出来,然后将js数据写进去,所以我们要使用正则表达式。
我的名字叫做<%name%>
上面代码使用正则获取<%name%>变量,然后将data中的name值替换,精简版js模板已经完成。嗯,哪怕这只是简单的字符串替换。
由于时间关系,暂时这样,明天有空继续补上。
------------------------2017-10-10---------------------
继续昨天代码,当对象为对象,字符串替换方式就失灵了,我们换一种方式去探索
<%name%> <%info.age%>
根据上面思路,我们继续,假若存在for循环,我们要怎么解析它的代码?将for循环转成字符串返回?嗯我们试试
let result = tmpl.replace(/<%([^%>]+)?%>/g,function(s0,s1){
return 'Posts: ' +
'for(var i = 0; i < post.length; i++) {'
'' + post[i].exper + ' }'
})
这段代码明显不行,为何?他会直接输出该字符串,我们要的是得到多个a标签和内容,所以我们需要分开保存,js数组上场了。
let result = [];
result.push('Post');
result.push('for(var i = 0; i < post.length; i++) {');
result.push('');
result.push(post[i].exper);
result.push('');
result.push('}');
上面使用数组装载for循环的语句和一些字符串,看起来完美,但事情没那么简单,这样子的数组都是字符串,无法转换,我们换一下
var r = [];
r.push('Posts: ' );
for(var i = 0; i < post.length; i++) {
r.push('');
r.push(post[i].exper);
r.push('');
}
这样子看来没问题了,那么我们怎么解析运行呢?这里要用到new Function()对象实例,可能很多人对function熟悉,但其实内部还是要经过new Function得到一个实例。我们可以使用另外一种方式创建函数
var function_name = new function(arg1, arg2, ..., argN, function_body)
在上面的形式中,每个 arg 都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。
是不是很熟悉?再看例子
function sayHi(sName, sMessage) {
alert("Hello " + sName + sMessage);
}
上面是普通的不能在普通的函数声明,那么new Function的
var sayHi
=
new Function("sName", "sMessage", "alert(\"Hello \" + sName + sMessage);");
回到正题来,我们要用new Function构建一个函数来运行我们的数组,我们先来看下直接运行相关代码样子
var fn = new Function("data",
"var r = []; for(var i in data){ r.push(data[i]); } return r.join(' ')");
fn({"name": "barretlee", "age": "20"}); // barretlee 20
<% for(var i = 0; i < post.length; i++) {+
<% post[i].expert %> +
<% } %>
fn函数中传入一个对象,返回一个字符串集合,join() 方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。所以思路就有了,我们可以把逻辑部分和非逻辑部分的代码链接成一个字符串,然后利用类似fn的函数直接编译代码。为了能够识别所有元素,我们要使用exec代替replace。
exec() 方法用于检索字符串中的正则表达式的匹配,返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null。
以下为w3cShool解释
说明
exec() 方法的功能非常强大,它是一个通用的方法,而且使用起来也比 test() 方法以及支持正则表达式的 String 对象的方法更为复杂。
如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string。我们可以看得出,在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用方法 String.match() 返回的数组是相同的。
但是,当 RegExpObject 是一个全局正则表达式时,exec() 的行为就稍微复杂一些。它会在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串 string。当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,您可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。
http://www.w3school.com.cn/jsref/jsref_exec_regexp.asp
var reg = /<%([^%>]+)?%>/g;
var tpl = 'Hei, my name is <%name%>, and I\'m <%age%> years old.';
var match = reg.exec(tpl);
console.log(match);
var reg = /<%([^%>]+)?%>/g;
while(match = reg.exec(tpl)) {
console.log(match);
}
<% for(var i = 0; i < this.posts.length; i++) {%>
<% this.posts[i].expert %>
<% } %>
参考链接:http://www.cnblogs.com/hustskyking/p/principle-of-javascript-template.html