本文主要是介绍【js模板引擎】萌新也能看懂的模板引擎,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
从一个实际需求出发认识模板引擎
实现一个模板引擎的思路及步骤
从一个实际需求出发认识模板引擎
当我们需要用js渲染一个歌曲列表的时候,由于数据需要向后端请求,所以实现不能在html中把数据写死。
如下所示,我们需要在页面上展示这样一个列表,
但是却不能像下面一样把数据写死在li标签中。
这个时候有两种我们容易思考得到的方法来解决这个问题,一个是html字符串拼接,另一种是构建DOM对象。
第一种:HTML字符串拼接
第二种:构建DOM对象
但是这两种方法都有很大缺陷:
第一种方法容易漏引号,出现拼接错误。
第二种方法则是代码量增加,虽然可以用jquery来减少代码量,但依然不是最优选择。
这两种方法的共同特征都是需要创建一个li标签,然后里面的内容动态获取
var li = '<li>'+ songs[i].name +'-'+songs[i].singer'</li>'
在这里我们可以使用一种更好的办法,
var li = stringFormat('<li>{0} - {1}</li>', songs[0].name, songs[0].singer)
构建一个stringFormat函数,向里面传入参数,第一参数是模板,{0},{1}会被后面传入的两个参数替换,这样当函数执行后返回的就是一个字符串
"<li>Some Like It Hot!! - SPYAIR</li>"
这个stringFormat函数可以说,就是一个最为粗略的模板引擎了。
传入的参数:
'<li>{0} - {1}</li>'
就是一个模板,所谓的模板引擎就是能够解析含有特殊字符的逻辑代码,简化字符串拼接前端渲染小插件。
但是这样的话,就必须把这部分函数写在script标签中,否则无法区分哪部分是html代码,哪部分是逻辑代码,所以我们需要特殊的字符来表示,这个特殊的字符就是定界符,
比如这个模板,使用的定界符就是<%%>:
'<p>Hello, my name is <%name%>. I\'m <%age%> years old.</p>';
实现一个模板引擎的思路及步骤:
以上举例的模板还并不算复杂,当我们遇到下面这个模板的时候,情况就会变得不同。
var template =
'My skills:' +
'<%if(this.showSkills) {%>' +'<%for(var index in this.skills) {%>' + '<a href="#"><%this.skills[index]%></a>' +'<%}%>' +
'<%} else {%>' +'<p>none</p>' +
'<%}%>';
var data = {skills: ["js", "html", "css"],showSkills: true
}
var TemplateEngine = function(template, data) {return string
}
现在需要理清楚我们的思路,我们拿到一个模板,需要让它里面有定界符包裹的代码能够像js代码一样运行,最后返回给我们一个包含了运行结果的字符串,我们现在需要的就是实现
1. 创建一个新数组,将没有定界符包裹的代码部分放入数组中
2. 分辨出js逻辑部分,也就是有定界符包裹的部分,取出,
3. 传入data
这样最后返回给我们的就是这样一个字符串,
最终代码如下:
var TemplateEngine = function(html, options) {var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n', cursor = 0;var add = function(line, js) {js? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :(code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');return add;}while(match = re.exec(html)) {add(html.slice(cursor, match.index))(match[1], true);cursor = match.index + match[0].length;}add(html.substr(cursor, html.length - cursor));code += 'return r.join("");';return new Function(code.replace(/[\r\t\n]/g, '')).apply(options);
}
可能很多人看不懂这个最终版本,下面我将把这个复杂版本简单化,添加注释,以便于理解:
var TemplateEngine = function(html, options) {//正则匹配出<%%>包裹的逻辑代码部分var re = /<%([^%>]+)?%>/g;//正则匹配出含有if|for|else|switch|case|break|{|}等关键字var reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g;//声明一个字符串code,用来保存我们最终输出的结果var code = 'var r=[];\n';//设置一个游标,用来遍历完我们传入的整个模板字符串var cursor = 0;//声明一个add函数,用来判断是js脚本部分,还是需要添加到数组中的字符串部分var add = function(line, js) {if(js === true){if(line.match(reExp)){code = code + line + '\n'}else{code = code + 'r.push(' + line + ');\n'}}else{if(line !== ''){code = code + 'r.push("' + line.replace(/"/g, '\\"') + '");\n'; //引号添加转义符}else{code = code + ''}}return add}while( match = re.exec(html) ) {var matchIdx = match.index;//使用re正则匹配,在模板字符串中匹配到的第一个部分的最后一个字符的下一个字符的下标var matchPart = html.slice(cursor,matchIdx);//从模板字符串中截取出下标从cursor,到matchIdx的部分add(matchPart);//只传了第一参数,lineadd(match[1], true); //第二个参数设为true的话,直接进入if(js===true)这个判断中cursor = match.index + match[0].length; //游标更新}var rest = html.substr(cursor, html.length - cursor);//匹配结束后,模板字符串中最后剩余的部分add(rest);//这一部分也需要进入add函数中判断code = code + 'return r.join("");';//最后添加返回语句code = code.replace(/[\r\t\n]/g, '');//去除code字符串中的制表符,回车符和换行符等,使代码看起来更加简洁return new Function(code).apply(options); //将code放入Function()函数中运行,并且将code中的变量作用域绑定到data上。
}
最终我们会获得这样一个字符串code,
利用JS给我们提供了构造函数的“类”,
可以运行code
注意
这里之所以会报错,是因为console.log中添加的双引号没有加上转义符(\),所以会报错
完结:
写完这篇博客断断续续差不多用了两天的时间,理解一个东西不难,但是怎么用文字说明白就很伤脑筋了,不过也算是前进了一小步啦。
参考博客
这篇关于【js模板引擎】萌新也能看懂的模板引擎的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!