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
函数传参
, 用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 world
<% 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 <%%>
, umhüllt von , js-Variable Der Platzhalter <%= %>
wird von umschlossen, und der Rest ist der gewöhnliche Teil der HTML-Zeichenfolge
<%%>
<%=%>
纯文本
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!