简易前端模板引擎

模板解析

解决的问题:

将data和js+html片段解析成html片段,完成赋值和js逻辑,如下所示:
输入:
var data = {
    name: 'hwm',
    articles: [{ title: 'the first one' }, { title: 'the last one' }]
};
tpl = '<p>Hi my name is <%this.name%>.</p><p>My articles are listed as followed:</p>'
    + '<ul>'
    + '<%for(var i = 0; i < this.articles.length; i++) {%>'
    + '<li><%this.articles[i].title%></li>'
    + '<%}%>'
    + '</ul>';
输出:

核心思想:

(1)将js片段、赋值片段、html片段解析出来,主要依赖于正则表达式
// 匹配被标识的片段
var reg = /<%(.*?(?=%>))%>/g;
// 匹配if、for等开头的逻辑代码
var logicalReg = /^(( )?(if|for|while|else|{|}|switch|case|break))(.*)?/g;
(2)解析结果均是字符串,通过new Function()的方法,可以将字符串传入函数,当做函数体然后执行
于是在字符串的逻辑就是构建一个数组,然后将html和赋值片段push到数组,将逻辑片段添加到字符串,然后通过call将data传入函数体并执行;
// 匹配被标识的片段
var reg = /<%(.*?(?=%>))%>/g;
// 匹配if、for等开头的逻辑代码
var logicalReg = /^(( )?(if|for|while|else|{|}|switch|case|break))(.*)?/g;
var match;
var result = 'var result = [];\n';
var index = 0;
// 使用exec方法,得到匹配内容和匹配结果
while (match = reg.exec(tpl)) {
    addCode(tpl.slice(index, match.index));
    addCode(match[1], true);
    index = match.index + match[0].length;
}
addCode(tpl.slice(index, tpl.length));
result += 'return result.join("")';
result = result.replace(/[\t\n\r]/g, '');
return new Function(result);

function addCode(code, isJs) {
    // 保证赋值代码不被引号包裹,js逻辑代码直接拼在字符串中
    isJs ? result += (code.match(logicalReg) ? code + '\n' : 'result.push(' + code + ');\n')
        : result += 'result.push("' + code.replace(/"/g, '\\"') + '");\n';
}
(3)建立缓存,当数据变化,模板没有变化时,直接从缓存中调用即可,无需重复解析;
(function () {
    var cache = {};
    this.tmpl = function (id, tpl, data) {
        var parser = cache[id] || function () {
                // 解析代码,同上
        }();
        cache[id] = parser;
        return parser.call(data);
    };

})();
 
备注:主要参考文章链接如下
 
posted @ 2016-06-19 16:54  Young Dreamer  阅读(1014)  评论(2编辑  收藏  举报