什么是模板引擎?
举个例子,当我们需要渲染一段html,而这段html中包含了很多结构一样的li标签,仅仅是内容不同(内容来自渲染的数据),我们就可以把这段具有相同结构的li的html片段提取出来作为模板,需要渲染的数据用规定的语法来表示。通过一个渲染函数,将模板和需要渲染的数据作为参数传入这个函数,最终这个渲染函数返回被渲染好的html片段,然后再写入dom。
一个简单的示例
var TemplateEngine = function(tpl, data) {
// 此处为渲染函数的代码
}
// 此处为模板,需要渲染的参数按照<%name%>的形式指定
var template = '<p>Hello, my name is <%name%>. I\'m <%age%> years old.</p>';
console.log(TemplateEngine(template, {
name: "Krasimir",
age: 29
}));
复制代码
以上这段函数,我们希望把传入的数据渲染到模板对应的字段,最终输出如下字符串
<p>Hello, my name is spanKrasimir. I\'m 29 years old.</p>
复制代码
抛开渲染函数函数体不谈,以上就是一个简单的模板引擎的实现原理。
实现原理
想要渲染函数实现我们的需求,第一个想的方法就是--正则表达式。在TemplateEngine 函数中,我们可以先定义一个正则表达式,用来匹配模板参数,也就是上文我们定义的<%name%>,其规则是:渲染参数被'<%'和'%>'包裹。那么我们的正则规则可以定义如下:
var re = /<%([^%>]+)?%>/g;
复制代码
这个正则的含义如下图,即匹配以'<%'和'%>'包裹且内容不包含'%'或'>'的内容
既然有了正则,我们先使用它来匹配我们的模板看下结果,这里我们使用exec方法来进行匹配,exec方法的具体用法和介绍可参考MDN 代码如下:
var re = /<%([^%>]+)?%>/g;
var match = re.exec(tpl);
复制代码
将match打印出来,得到的结果如图:
match[0]就是正则表达式匹配到的字符串,match[1]就是正则表达式匹配结果的第一个分组,分组的概念这里不多做介绍,可网上查看。但是这里我们又发现一个奇怪的地方,我的正则明明写的是全局匹配啊,按理来说这段模板字符串应该匹配到两个字符串啊,客观莫慌,接下来就介绍match.index这个属性,我们从第一次exec的结果可以看到,match.index=21,这个值就是匹配到第一个符合规则的字符串的索引位置,这可以说是exec方法的一个特性,如果我们想要匹配到后面的'<%age%>'字符串,那么我们只需要再执行一次exec方法,第二次执行会从上一次执行后的index值开始匹配,多次执行按照此规律进行,直至匹配到最后结束返回null。 为了匹配到所有的符合条件的模板字符串,我们将代码改成如下所示:
var re = /<%([^%>]+)?%>/g;
var match = '';
while(match = re.exec(tpl)){
console.log(match)
}
复制代码
输出结果如图
到了这里,我们就能把模板中所有符合规则的字段匹配出来了,接下来要做的就是将数据用replace替换进去,我们可以在TemplateEngine中这样写:
var TemplateEngine = function(tpl, data) {
var re = /<%([^%>]+)?%>/g, match;
while(match = re.exec(tpl)) {
tpl = tpl.replace(match[0], data[match[1]])
}
return tpl;
}
复制代码
将模板和数据传入这个函数,返回值如下:
至此,我们已经写出了一个简单的模板引擎,当传入模板和数据时,可以返回渲染后的数据。