Heim > Web-Frontend > js-Tutorial > Hauptteil

Einfache Schreibmethode für die JS-Template-Engine

一个新手
Freigeben: 2017-10-20 10:30:03
Original
2413 Leute haben es durchsucht

Vorderseite

Es gibt viele, viele JS-Template-Engines. Früher habe ich oft Art-Template verwendet, und manchmal verwende ich auch Vue als Template-Engine.

Bis...

Anfang des Jahres war ich noch im vorherigen Projektteam. Damals lautete die Codespezifikation Sie können nicht [externen Code] verwenden. ohne Erlaubnis, peinlich.

Wenn Bedarf besteht, dann schreiben Sie es, aber später wurde es aus bestimmten Gründen nicht verwendet. Später teilten wir die Produktionslinie auf und erstellten eine Reihe von Builds. Nachdem ich sie einige Monate lang verwendet hatte, schrieb ich diesen kleinen Code nach gängigeren Standards um und teilte ihn mit allen.

https://github.com/shalldie/mini-tpl

Grammatik

Die erste besteht darin, die Vorlagensyntax auszuwählen. Die EJS-Syntax ist die erste Wahl, da die Die Öffentlichkeit muss Dinge wie Direktiven-Template-Engines nicht lernen.

Wenn Sie jsp oder asp/asp.net geschrieben haben, können Sie direkt loslegen.

Wie benutzt man es?

Ich möchte es so verwenden

<body>
        <p id="root"></p>
        <script id="tplContent" type="text/html">
        <ul>
            <% for(var i=0; i<data.length; i++){
                var item = data[i];
                if(item.age < 30){%>
                    <li>我的名字是<%=item.name%>,我的年龄是<%=item.age%></li>
                <%}else{%>
                    <li>my name is <%=item.name%>,my age is a sercet.</li>
                <%}%>
            <% } %>
        </ul>
        </script>
        <script src="../build/mini-tpl.min.js"></script>
        <script>
            var data = [{ name: &#39;tom&#39;, age: 12 }, { name: &#39;lily&#39;, age: 24 }, { name: &#39;lucy&#39;, age: 55 }];
            var content = document.getElementById(&#39;tplContent&#39;).innerHTML;
            var result = miniTpl(content, data);
            document.getElementById(&#39;root&#39;).innerHTML = result;
        </script>
    </body>
Nach dem Login kopieren

Wenn Sie es so verwenden möchten, dann analysieren wir, wie Sie es erreichen können.

neue Funktion

    1 const content = &#39;console.log("hello world");&#39;;    
    2 
    3 let func = new Function(content);    
    4 
    5 func(); // hello world
Nach dem Login kopieren
new Function ([arg1[, arg2[, ...argN]],] functionBody)
Nach dem Login kopieren

functionBody Ein JavaScript语句的<strong>字符串</strong>String

JavaScript-Anweisung enthält, die die Funktionsdefinition enthält >. <p class="panel panel-default" style="padding: 20px;"><br/>Mit dem Funktionskonstruktor generierte Funktionen erstellen keine Abschlüsse in dem Kontext, in dem sie erstellt werden. Sie werden im Allgemeinen im globalen Bereich erstellt. </p>Wenn diese Funktionen ausgeführt werden, können sie nur auf ihre eigenen lokalen Variablen und globalen Variablen zugreifen und nicht auf den Bereich des Kontexts, der vom aufgerufenen Funktionskonstruktor generiert wird. (MDN)<p></p>Mit anderen Worten: <ol class=" list-paddingleft-2"><li><p></p>Sie können eine neue Funktion verwenden, um dynamisch eine Funktion zu erstellen und eine dynamisch generierte Funktionsdefinitions-JS-Anweisung auszuführen. </li><li><p></p>Die von new Function generierte Funktion hat einen globalen Geltungsbereich. </li><li><p><code>把变量放到全局(扯淡) Dann gibt es drei Arten von Parametern: 函数传参, 用call/apply把值传给函数的this,

.

Zuerst habe ich call verwendet, um den Wert zu übergeben, aber als ich jetzt darüber nachdachte, war es nicht sehr elegant, also bin ich dazu übergegangen, es über Parameter zu übergeben. Das ist es:
const content = &#39;console.log(data);&#39;;
    
    let func = new Function(&#39;data&#39;, content);
    
    func(&#39;hello world&#39;); // hello world
Nach dem Login kopieren

Das ist es, der Prototyp ist da. Lassen Sie es uns unten aufschlüsseln.

Vorlagenaufteilung

Sehen Sie sich zuerst die Vorlage an:
<% for(var i=0; i<data.length; i++){        
var item = data[i];        
if(item.age < 30){%>
            <li>我的名字是<%=item.name%>,我的年龄是<%=item.age%></li>
        <%}else{%>
            <li>my name is <%=item.name%>,my age is a sercet.</li>
        <%}%>
    <% } %>
Nach dem Login kopieren

js logischer Teil <%%>, umhüllt von , js-Variable Der Platzhalter <%= %> wird von umschlossen, und der Rest ist der gewöhnliche Teil der HTML-Zeichenfolge

, der gespleißt werden soll.

Mit anderen Worten, es gibt drei Arten von Teilen, die mithilfe regulärer Ausdrücke gefunden werden müssen:
  1. <%%>

    Der js-Inhalt des logischen Teils
  2. <%=%>

    Der js-Inhalt des Platzhalterteils
  3. 纯文本Andere

    Inhalte

js部分Der zweite item, js-Platzhalter Der Teil gehört auch zum gespleißten Text. So können sie zusammengesetzt werden, das heißt 拼接部分,

.

Reguläre Extraktion

Wählen Sie natürlich reguläre Ausdrücke!

Hier werde ich zunächst auf den Inhalt von Pseudo-Arrays eingehen und darauf, wie die Browserkonsole Pseudo-Arrays behandelt:

Ohne zu weit zu gehen, sagen wir einfach die Schlussfolgerung:

Solange es ein int-Typ-Längenattribut gibt, gibt es eines ein Funktionsspleiß

-Attribut vom Typ. Dann denkt der Browser, dass es sich um ein Array handelt.

Wenn die anderen darin enthaltenen Eigenschaften nach Index sortiert sind, können sie in der Konsole sogar wie Elemente in einem Array angezeigt werden.

Diese Beurteilungsmethode nennt man Ententypisierung

Wenn etwas wie eine Ente aussieht und wie eine Ente quakt, dann ist es eine Ente 0_o

Zurück zum Text, das hier erfordert das mehrmalige Extrahieren des logischen js-Teils und des Textes aus der Vorlage.

Für jede Extraktion muss der extrahierte Inhalt abgerufen werden. Diesmal wird das letzte Indexelement abgeglichen (wird zum Heben des Textinhalts verwendet). Also habe ich mich für RegExp.prototype.exec entschieden.

RegExp.prototype.exec gibt beispielsweise eine Sammlung (Pseudo-Array) zurück und ihr Typ ist wie folgt:
属性/索引描述
[0]匹配的全部字符串
[1],...[n]括号中的分组捕获
index匹配到的字符位于原始字符串的基于0的索引值
input原始字符串
<🎜>

通过这样,就可以拿到匹配到的 js 逻辑部分,并通过 index 和本次匹配到的内容,来获取每个js逻辑部分之间的文本内容项。

要注意,在全局匹配模式下,正则表达式会接着上次匹配的结果继续匹配新的字符串。

    /**
     * 从原始模板中提取 文本/js 部分
     * 
     * @param {string} content 
     * @returns {Array<{type:number,txt:string}>} 
     */
    function transform(content) {
        var arr = [];                 //返回的数组,用于保存匹配结果
        var reg = /<%(?!=)([\s\S]*?)%>/g;  //用于匹配js代码的正则
        var match;   				  //当前匹配到的match
        var nowIndex = 0;			  //当前匹配到的索引        

        while (match = reg.exec(content)) {
            // 保存当前匹配项之前的普通文本/占位
            appendTxt(arr, content.substring(nowIndex, match.index));
            //保存当前匹配项
            arr.push({
                type: 1,  //js代码
                txt: match[1]  //匹配到的内容
            });
            //更新当前匹配索引
            nowIndex = match.index + match[0].length;
        }
        //保存文本尾部
        appendTxt(arr, content.substr(nowIndex));
        return arr;
    }

    /**
     * 普通文本添加到数组,对换行部分进行转义
     * 
     * @param {Array<{type:number,txt:string}>} list 
     * @param {string} content 
     */
    function appendTxt(list, content) {
        content = content.replace(/\r?\n/g, "\\n");
        list.push({ txt: content });
    }
Nach dem Login kopieren

得到了js逻辑项 和 文本内容 ,就可以把他们拼在一起,来动态生成一个function。要注意的是,文本内容中,包含 js占位项,这个地方要转换一下。

    /**
     * 模板 + 数据 =》 渲染后的字符串
     * 
     * @param {string} content 模板
     * @param {any} data 数据
     * @returns 渲染后的字符串
     */
    function render(content, data) {
        data = data || {};
        var list = [&#39;var tpl = "";&#39;];
        var codeArr = transform(content);  // 代码分割项数组

        for (var i = 0, len = codeArr.length; i < len; i++) {
            var item = codeArr[i]; // 当前分割项

            // 如果是文本类型,或者js占位项
            if (!item.type) {
                var txt = &#39;tpl+="&#39; +
                    item.txt.replace(/<%=(.*?)%>/g, function (g0, g1) {
                        return &#39;"+&#39; + g1 + &#39;+"&#39;;
                    }) + &#39;"&#39;;
                list.push(txt);
            }
            else {  // 如果是js代码
                list.push(item.txt);
            }
        }
        list.push(&#39;return tpl;&#39;);

        return new Function(&#39;data&#39;, list.join(&#39;\n&#39;))(data);
    }
Nach dem Login kopieren

这样就完成了简易的模板引擎,不要觉得拼字符串慢。

在现代浏览器(IE8开始)中,特地对字符串的操作做了大量的优化,用 += 拼字符串,要比用数组 push 再 join 的方式快很多很多,即使放到IE7(IE6不清楚)中,我这里测试也是拼字符串快。。。

Das obige ist der detaillierte Inhalt vonEinfache Schreibmethode für die JS-Template-Engine. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage