Il existe de très nombreux moteurs de modèles js. J'utilisais souvent art-template, et parfois j'utilise aussi vue comme moteur de modèles.
Jusqu'à...
Au début de l'année, j'étais encore dans l'équipe de projet précédente. A cette époque, la spécification du code était Vous ne pouvez pas utiliser [code externe]. sans autorisation, embarrassant.
S'il y a un besoin, écrivez-le, mais plus tard, il n'a pas été utilisé pour certaines raisons. Plus tard, nous avons divisé la chaîne de production et construit moi-même un ensemble de builds. Après l'avoir utilisé pendant quelques mois, je me suis senti très à l'aise, j'ai réécrit ce petit morceau de code selon des normes plus populaires et je l'ai partagé avec tout le monde.
https://github.com/shalldie/mini-tpl
La première est de choisir la syntaxe du modèle, la syntaxe ejs est le premier choix, car le le public n'a pas besoin de l'apprendre. Des choses comme les moteurs de modèles de directives.
Si vous avez écrit jsp ou asp/asp.net, vous pouvez commencer directement.
<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>
Si vous souhaitez l'utiliser comme ça, analysons comment y parvenir.
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 Une JavaScript语句的<strong>字符串</strong>
chaîne
函数传参
, 用call/apply把值传给函数的this
, . Au début, j'utilisais call pour transmettre la valeur, mais maintenant que j'y pense, ce n'était pas très élégant, alors j'ai changé pour la transmettre par paramètres. Ça y est : 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> <%}%> <% } %>
partie logique js <%%>
, enveloppée par , variable js L'espace réservé <%= %>
est enveloppé par , et le reste est la partie chaîne HTML
<%%>
<%=%>
纯文本
Autre
js部分
Le deuxième item, js placeholder La partie appartient également au texte épissé. Pour qu'ils puissent être assemblés, c'est-à-dire 拼接部分
,
Tant qu'il y a un attribut length de type int, il y a est un attribut function splice
de type. Le navigateur pensera alors qu'il s'agit d'un tableau. Si les autres propriétés à l'intérieur sont triées par index, elles peuvent même être affichées dans la console comme les éléments d'un tableau.Cette méthode de jugement s'appelle typage du canard
Si quelque chose ressemble à un canard et cancane comme un canard, alors c'est un canard 0_oRetour au texte, ceci. nécessite d'extraire plusieurs fois la partie logique js et le texte du modèle. Pour chaque extraction, le contenu extrait doit être obtenu. Cette fois, le dernier élément d'index est mis en correspondance (utilisé pour lever le contenu du texte). J'ai donc choisi RegExp.prototype.exec . Par exemple, RegExp.prototype.exec renvoie une collection (pseudo-tableau), et son type est le suivant :属性/索引 | 描述 |
---|---|
[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不清楚)中,我这里测试也是拼字符串快。。。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!