Web前端模板引擎の字符串模板

这是一个系列文章,将会引见现在Web前端范畴里用到的三种模板引擎手艺,它们分别是:

  • 基于字符串的模板

  • 基于Dom操纵的模板

  • 基于假造Dom的模板

本文是这个系列的第一篇,偏重引见基于字符串的模板引擎的完成道理,剖析它的长处瑕玷以及运用的场景。

进入正文之前,我们先回忆一下在模板引擎涌现之前,暂时称之为“石器时代”,我们是怎样运用JS转变页面构造的。关于下面的代码:

<div id="container">
    我们正处于刀耕火种的石器时代
</div>

假如我们须要修正container内里的内容,平常有2种方法:

  • 经由过程JS的DOM API直接操纵DOM

    var newTxt = '石器时代须要本身撸东西,磨擦磨擦,似魔鬼的步调...';
    var container = document.getElementById('container');
    var desc = document.createElement('H1');
    var txt = document.createTextNode(newTxt);
    desc.appendChild(txt);
    container.replaceChild(desc, container.childNodes[0]);
  • 经由过程innerHTML批量修正DOM构造

    var newTxt = '石器时代须要本身撸东西,磨擦磨擦,似魔鬼的步调...';
    var template = '<H1>' + newTxt + '</H1>';
    var container = document.getElementById('container');
    container.innerHTML=template;

相比之下,第二种体式格局经由过程innerHTML更新DOM要简朴很多,它无需斟酌DOM的层级构造,只要做简朴的字符串拼接就可以完成需求。但这类体式格局的问题是代码可读性很差,同时开发者还必须保证终究拼接的字符串的正确性。当须要作出修正时,面临一坨的字符也很痛楚。

在上面的例子中,我们的需求是将一个变量注入到模板当中,相似ES6的模板字符串:

var newTxt = '石器时代须要本身撸东西,磨擦磨擦,似魔鬼的步调...';
var template = `<H1>${newTxt}</H1>`;

但ES6这类现代化的常规武器,对石器时代而言是天方夜谭。部落里的老司机依附深挚的JS功底,撸出了种种基于字符串的模板。这些模板又可以细分为2类:一种是不包括逻辑处置惩罚,只作数据绑定用的,如mustache.js;另一种是既有逻辑处置惩罚,也有数据绑定的,如EJS

下面,我以EJS的语法为例,完成一个简朴的字符串模板引擎。模版引擎的编译流程以下:
《Web前端模板引擎の字符串模板》

1.起首,须要编译模板字符串,将其转换为JS可以明白的语法。第一步是运用正则表达式,辨别出字符串中哪些是模板语法,哪些是一般的HTML标签。以下是一个EJS语法的例子:

<ul>
    <% for(var i=0; i<supplies.length; i++) {%>
        <li><%= supplies[i] %></li>
    <% } %>
</ul>

在‘<%=’和‘%>’之间是JS的表达式,而在‘<%’和’%>‘之间是一般的JS语句,可以举行逻辑推断和前提轮回等操纵。可以运用以下正则表达式抽取:

// 婚配表达式,只能有一行
let evalExpr = /\<\%\=(.+?)\%\>/g;

// 婚配语句,可以有多行
let expr = /\<\%([\s\S]+?)\%\>/g;

关于一般的HTML标签,须要用自定义的echo函数包裹一下,在运用eval函数编译的时刻直接输出字符串。echo函数的定义以下:

// 暂时变量,保留编译后的模板字符串
let output = "";
  
// 直接将html字符串拼接到output背面
function echo(html){
    output += html;
}

完全的compile函数代码以下:

function compile(template){
  
    // 婚配表达式,只能有一行
    let evalExpr = /\<\%\=(.+?)\%\>/g;
  
    // 婚配语句,可以有多行
    let expr = /\<\%([\s\S]+?)\%\>/g;
  
    // 内容为空的部份
    let empty = /echo\(\"\"\);/g;
  
    template = template
        // 转换JS表达式
        .replace(evalExpr, '`); \n echo( $1 ); \n echo(`')
    
        // 转换JS语句
        .replace(expr, '`); \n $1 \n echo(`');
  
    // 在模板的最外层包裹一个echo
    template = 'echo(`' + template + '`);';
  
    // 消灭空的echo
    template = template
        .replace(empty, "");
  
    // 保留编译后的字符串,此处用了ES6的模板字符串特征,相当于eval了一下
    let script = 
        `(function parse(data){
  
            // 暂时变量,保留编译后的模板字符串
            var output = "";
  
            // 直接将html字符串拼接到output背面
            function echo(html){
                output += html;
            }
  
            // 包括echo的模板字符串
            ${ template }
  
            return output;
        })`;
    
    return script;
}

经由正则表达式处置惩罚后,这段代码:

<ul>
    <% for(var i=0; i<supplies.length; i++) {%>
        <li><%= supplies[i] %></li>
    <% } %>
</ul>

会转化为:

    echo(`<ul>`); 
        for(var i=0; i<data.supplies.length; i++) { 
            echo(`<li>`); 
                echo( data.supplies[i] ); 
            echo(`</li>`); 
        }  
    echo(`</ul>`);

完全代码亦可见JSFiddle

2.第二步,我们将模板中用到的数据data注入到compile函数的parse子函数中,天生终究的字符串。

3.末了,我们再经由过程innerHTML,把字符串插进去到DOM适宜的位置。

字符串模板之所以可以更新页面,最中心的道理是运用innerHTML这个api将字符串直接插进去到DOM节点中。因而,我们剖析字符串模板的优瑕玷就离不开运用innerHTML更新DOM的优瑕玷。先谈谈长处:

  1. 直观,轻易明白。更新后的DOM构造可以一览无余的反映在字符串当中。

  2. 轻易保护。当须要变动模板时,直接改响应字符串就可以够,新人也轻易上手。

  3. 可用于服务端衬着。简朴的字符串拼接,不依赖DOM,对应的字符串可由服务器端直接天生。

再来谈谈瑕玷:

  1. 安全隐患。模板字符串中完全可以涌现此类代码:<img src=”69″ onerror=”alert(‘xss’)”>

  2. 慢!迥殊关于须要频仍更新的场景。因为innerHTML是直接替换掉原有元素,因而就涉及到响应节点和对应事宜的卸载,然后再装载新的节点和事宜。在这个过程当中,界面也会被重排和重绘,对机能是严峻的消耗。

  3. 不智能。当只须要修正模板内里的某一部份数据时,全部模板页都须要被革新。

  4. 保护难题。这不是打脸嘛,上面才说了轻易保护,这里又讲保护难题!?这当然是有缘由的嘛。当不须要斟酌机能的时刻,一个页面能够只须要保护一个模板,这难道不简朴?但斟酌到机能的时刻,就须要对模板举行拆分和拼装,保护这些相互依赖的模板会让人很崩溃。

综上所述,我们可以很简朴的总结出字符串模板引擎的运用场景:假如你的运用比较简朴,交互也不多,也愿望有一个疾速的首屏时候,请运用字符串模板引擎。反之,你硬要上字符串模板引擎的话,我发起你先看看我下一期或许下下一期的文章再做决议,哈哈哈哈~

未完待续…

    原文作者:dabai
    原文地址: https://segmentfault.com/a/1190000010313795
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞