JS模板引擎的实现原理

1.正则抠出要匹配的内容

针对这一串代码,通过正则获取内容

var tpl = 'Hei, my name is <%name%>, and I\'m <%age%> years old.';
var data = {
    "name": "Barret Lee",
    "age": "20"
};

最简单的方式就是通过replace函数了:

var result = tpl.replace(/<%([^%>]+)?%>/g, function(s0, s1){
    return data[s1];
});
注:replace()方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
语法:
stringObject.replace(regexp/substr,replacement)
参数描述
regexp/substr

必需。规定子字符串或要替换的模式的 RegExp 对象。

请注意,如果该值是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为 RegExp 对象。

replacement 必需。一个字符串值。规定了替换文本或生成替换文本的函数。

 返回值

  一个新的字符串,是用 replacement 替换了 regexp 的第一次匹配或所有匹配之后得到的。

 说明

  字符串 stringObject 的 replace() 方法执行的是查找并替换的操作。它将在 stringObject 中查找与 regexp 相匹配的子字符串,然后用 replacement 来替换这些子串。如果 regexp 具有全局标志 g,那么 replace() 方法将替换所有匹配的子串。否则,它只替换第一个匹配子串。

replacement 可以是字符串,也可以是函数。如果它是字符串,那么每个匹配都将由字符串替换。但是 replacement 中的 $ 字符具有特定的含义。

返回一个这样的结果

'Posts: ' 
for(var i = 0; i < post.length; i++) {
    '<a href="#">' + post[i].exper + '</a>'
}
但是我们需要得到的是一个字符串,而不是上面这样零散的片段,因此可以把这些东西装入数组中。

2.装入数组

var r = [];
r.push('Posts: ' );
for(var i = 0; i < post.length; i++) {
    r.push('<a href="#">');
    r.push(post[i].exper);
    r.push('</a>');
}

这样的逻辑就十分完善了,不存在太多的漏洞,但是这个转化的过程是如何实现的?我们必须还是要写一个解析的模板函数出来。


3.分辨js逻辑部分

var reg = /<%([^%>]+)?%>/g;
while(match = reg.exec(tpl)) {
    console.log(match);
}

主要是靠match的index属性来定位遍历位置,然后利用while循环获取所有的内容。


4.引擎函数

我们并需要for,if,switch等这些东西也push到r数组中去,所以呢,还得改善下上面的代码,如果在line中发现了包含js逻辑的代码,我们就不应该让他进门:

regOut = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g;
var add = function(line, js) {
    js? code += line.match(regOut) ? line + '\n' : 'r.push(' + line + ');\n' :
        code += 'r.push("' + line.replace(/"/g, '\\"') + '");\n';
};

所以我们只剩下最后一步工作了,把data扔进去!


5.把data扔进去

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("");';
    return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
};
 

 

posted @ 2015-09-06 16:17  余珣  阅读(232)  评论(0编辑  收藏  举报