20 行代码实现模板引擎

摘要:实现功能 : 变量值的替换、if / else 及 for 循环等复杂操作。利用 exec 方法将变量替换为对象属性值,注意此方法输出的是一个数组,形如下方代码。

实现功能 : 

变量值的替换、if / else 及 for 循环等复杂操作。

// 最终效果
var opt = {
    hero: {
        name: 'Flash',
        age: 22,
    },
    skills: [
        'time travel',
        'speed force',
        'strike lightening'
    ]
}

var str = 
'<p>' 
    + '<% if( this.hero.name ) { %>'
    + '<b><% this.hero.name %></b>'
    + '<b><% this.hero.age %></b>'
    + '<% for ( let val of opt.skills ) { %>'
    + '<span><% val %></span>'
    + '<% } %>'
    + '<% } %>'
    + '</p>';

console.log(template(str, opt));

/* 
<p><b>Flash</b><b>22</b><span>time travel</span><span>speed force</span><span>strike lightening</span></p>
 */


核心代码 :

function template(html, options) {
    var rule = /<%(.+?)%>/g,
        ruleExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g,
        code = 'var arr = [];',
        cursor = 0,
        match;
    var add = function(line, js) {
        js 
        ? (code += line.match(ruleExp) ? line : 'arr.push(' + line + ');')
            : (code += line != '' ? 'arr.push("' + line.replace(/"/g, '\\"') + '");' : line);
        return add;
    }
    while( match = rule.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 arr.join("");';
    return new Function(code.replace(/[\
\	\
]/g, ' ')).apply(options);
}


难点解析 :

首先搞清楚两段正则表达式所表示的意思。

var rule = /<%(.+?)%>/g 指的是匹配 <% %> 中的值。

var ruleExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g 则匹配 <% %> 中含有的 JS 语句。

利用 exec 方法将变量替换为对象属性值,注意此方法输出的是一个数组,形如下方代码。

[
    "<%name%>",
    " name ", 
    index: 21,
    input: 
    "<p>Hello, my name is <%name%>. I\'m <%age%> years old.</p>"
]

利用 cursor 与 index 分割模板与普通字符串,即当遇到 <% %> 时就分割,不属于模板内的直接用 push 方法将字符串传入 arr 中,此时注意转义 " 符号。属于模板中的值则进行进一步的判断,当值为语句时则不 push 到 arr 中,当值为变量时则需要将变量 push 到 arr 中。

利用 arr.join("") 方法将数组转换为字符串并用正则将字符串里面的空格全部替换掉。

最后使用 new Function(code).apply(options) 让字符串代码变得可执行,apply 的作用则是让值的引用指向正确的对象,即确保 this 指向正确。

原文来自:https://github.com/RetroAstro/cosmos-blog/blob/master/posts/6.md


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_5605