ejs v9 模板系统:恢复 v6 风格与变量调试优化

作者:霁月

时间:2026-10-26

浏览:458

本文介绍 ejs v9 版本的更新内容,重点恢复 v6 风格,要求后端数据变量带 @ 前缀以便前端调试。新特性包括自动处理输出语句中的分号或逗号,防止报错。通过示例展示模板结构、JS 代码及核心源码逻辑,帮助开发者理解数据验证与模板解析机制。

文章目录

ejs v9 版本更新与变量调试优化

本版本旨在恢复 v6 的形态,后端数据变量仍保留 @ 前缀,以便前端查看与调试。此前已与一位腾讯前端工程师讨论过此必要性。通过获取模板中需填写的变量,并与后端传来的 JSON 进行比较,可实现早期数据验证。这种技术与 PHP 变量命名类似,均带有 $ 前缀标识。


在之前的版本中,如果输出语句带有分号或逗号,将会导致报错。


代码如下:

 
<script type="tmpl" id="table_tmpl">
<table>
<& for(var i=0,tl = @trs.length,tr;i<tl;i++){ &>
<& tr = @trs[i]; &>
<tr>
<td><&= tr.name; &></td> <td><&= tr.age; &></td> <td><&= tr.sex || "男" &></td>
</tr>
<& } &> 
</table>
<&# 怎么可能不支持图片 &>
<img src="<&= @href &>">
</script>

因为内部生成的字符串是这个样子的:


__views(data.tr.name;)


为了防止用户顺手把个逗号或分号上去,本版本自动帮你处理了.


代码如下:

 
rlastSemi = /[,;]\s*$/
// 略
case "="://处理后台返回的变量(输出到页面的);
logic = els[0].substring(1);
if(logic.indexOf("@")!==-1){
temp.push( startOfHTML, logic.replace(rAt,"$1data.").replace(rlastSemi,''), endOfHTML );
}else{
temp.push( startOfHTML, logic.replace(rlastSemi,''), endOfHTML );
} 
break;

模板使用示例与数据绑定

例子


下面是一个模板,放置于浏览器会忽略解析JS代码的script标签之内, 注意trs与href前面都带有@标识符。


代码如下:

 
<script type="tmpl" id="table_tmpl">
<table>
<& for(var i=0,tl = @trs.length,tr;i<tl;i++){ &>
<& tr = @trs[i]; &>
<tr>
<td><&= tr.name &></td> <td><&= tr.age &></td> <td><&= tr.sex || "男" &></td>
<&# 导入子模板 &>
<&= $.ejs("tds_tmpl"); &>
</tr>
<& } &> 
</table>
<&# 怎么可能不支持图片 &>
<img src="<&= @href &>">
</script>
<!-- 这是子模板 -->
<script type="tmpl" id="tds_tmpl">
<td>静态的表格</d> <td>静态的表格</d> <td>静态的表格</d>
</script>

这是它的JS代码:


代码如下:

 
$.require("ready,more/ejs,node", function(){
var trs = [
{name:"隐形杀手",age:29,sex:"男"},
{name:"索拉",age:22,sex:"男"},
{name:"fesyo",age:23,sex:"女"},
{name:"恋妖壶",age:18,sex:"男"},
{name:"竜崎",age:25,sex:"男"},
{name:"你不懂的",age:30,sex:"女"}
] 
var html = $.ejs("table_tmpl",{
trs: trs,
href: "https://www.jb51.net//rubylouvre/202906/o_type4.jpg"
}); 
$("#table_tc").html(html)
}); 

ejs v9 版本更新与变量调试优化

ejs 核心源代码解析

ejs源代码


代码如下:

 
$.define("ejs", "lang",function(){
var
_startOfHTML = "\t__views.push(",
_endOfHTML = ");\n",
sRight = "&>",
rLeft = /\s*<&\s*/,
rRight = /\s*&>\s*/,
rAt = /(^|[^\w\u00c0-\uFFFF_])(@)(?=\w)/g,
rLastSemi = /[,;]\s*$/
var ejs2 = $.ejs = function(id,data){
data = data || {};
if( !ejs2[id] ){
var rleft = rLeft,
rright = rRight,
sright = sRight,
rlastSemi = rLastSemi,
startOfHTML = _startOfHTML,
endOfHTML = _endOfHTML, str , logic,
el = document.getElementById(id);
if (!el) throw "can not find the target element";
str = el.innerHTML;
var arr = str.trim().split(rleft),
buff = ["var __views = [];\n"],temp = [],i = 0,n = arr.length,els,segment;
while(i < n){//逐行分析,以防歧义
segment = arr[i++];
els = segment.split(rright);
if( ~segment.indexOf(sright) ){//这里不使用els.length === 2是为了避开IE的split bug
switch ( els[0].charAt(0) ) {
case "="://处理后台返回的变量(输出到页面的);
logic = els[0].substring(1);
if(logic.indexOf("@")!==-1){
temp.push( startOfHTML, logic.replace(rAt,"$1data.").replace(rlastSemi,''), endOfHTML );
}else{
temp.push( startOfHTML, logic.replace(rlastSemi,''), endOfHTML );
} 
break;
case "#"://处理注释
break;
default://处理逻辑
logic = els[0];
if(logic.indexOf("@")!==-1){
temp.push( logic.replace(rAt,"$1data."), "\n" );
}else{
temp.push( logic, "\n" );
} 
} 
//处理静态HTML片断
els[1] && temp.push(startOfHTML, $.quote( els[1] ), endOfHTML)
}else{
//处理静态HTML片断
temp.push(startOfHTML, $.quote( els[0] ), endOfHTML );
} 
} 
ejs2[id] = new Function("data",buff.concat(temp).join("")+';return __views.join("");');
return ejs2[id]( data )
} 
return ejs2[id]( data )
} 
}) 
// ejs v9!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章