Heim >Web-Frontend >js-Tutorial >Einfache Schreibmethode für die JS-Template-Engine
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
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.
<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: 'tom', age: 12 }, { name: 'lily', age: 24 }, { name: 'lucy', age: 55 }]; var content = document.getElementById('tplContent').innerHTML; var result = miniTpl(content, data); document.getElementById('root').innerHTML = result; </script> </body>
Wenn Sie es so verwenden möchten, dann analysieren wir, wie Sie es erreichen können.
1 const content = 'console.log("hello world");'; 2 3 let func = new Function(content); 4 5 func(); // hello world
new Function ([arg1[, arg2[, ...argN]],] functionBody)
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 = 'console.log(data);'; let func = new Function('data', content); func('hello world'); // hello worldDas ist es, der Prototyp ist da. Lassen Sie es uns unten aufschlüsseln. VorlagenaufteilungSehen 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> <%}%> <% } %>
js logischer Teil a4558806285d5b7820bdaa0b90aa4d26
, umhüllt von , js-Variable Der Platzhalter 332000003288cabbdff89f9a8e5a919b
wird von umschlossen, und der Rest ist der gewöhnliche Teil der HTML-Zeichenfolge
a4558806285d5b7820bdaa0b90aa4d26
4eed03230346664e54006e16f8581c1e
纯文本
Andere
js部分
Der zweite item, js-Platzhalter Der Teil gehört auch zum gespleißten Text. So können sie zusammengesetzt werden, das heißt 拼接部分
,
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_oZurü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 }); }
得到了js逻辑项 和 文本内容 ,就可以把他们拼在一起,来动态生成一个function。要注意的是,文本内容中,包含 js占位项,这个地方要转换一下。
/** * 模板 + 数据 =》 渲染后的字符串 * * @param {string} content 模板 * @param {any} data 数据 * @returns 渲染后的字符串 */ function render(content, data) { data = data || {}; var list = ['var tpl = "";']; var codeArr = transform(content); // 代码分割项数组 for (var i = 0, len = codeArr.length; i < len; i++) { var item = codeArr[i]; // 当前分割项 // 如果是文本类型,或者js占位项 if (!item.type) { var txt = 'tpl+="' + item.txt.replace(/<%=(.*?)%>/g, function (g0, g1) { return '"+' + g1 + '+"'; }) + '"'; list.push(txt); } else { // 如果是js代码 list.push(item.txt); } } list.push('return tpl;'); return new Function('data', list.join('\n'))(data); }
这样就完成了简易的模板引擎,不要觉得拼字符串慢。
在现代浏览器(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!