Node 开源模板的选择很多,但推荐像我这样的老人去用 EJS,有 Classic ASP/PHP/JSP 的经验用起 EJS 来的确可以很自然,也就是说,你能够在 <%...%> 块中安排 JavaScript 代码,利用最传统的方式 <%=输出变量%>(另外 <%-输出变量是不会对 & 等符号进行转义的)。安装 EJS 命令如下:
npm install ejs
JS 调用
JS 调用的方法主要有两个:
ejs.compile(str, options); // => Function ejs.render(str, options); // => str
实际上 EJS 可以游离于 Express 独立使用的,例如:
var ejs = require(\'\'), str = require(\'fs\').readFileSync(__dirname + \'/list.ejs\', \'utf8\'); var ret = ejs.render(str, { names: [\'foo\', \'bar\', \'baz\'] }); console.log(ret); 见 ejs.render(),第一个参数是 模板 的字符串,模板如下。 <% if (names.length) { %> <ul> <% names.forEach(function(name){ %> <li foo=\'<%= name + \"\'\" %>\'><%= name %></li> <% }) %> </ul> <% } %>
names 成了本地变量。
选项参数
第二个参数是数据,一般是一个对象。而这个对象又可以视作为选项,也就是说数据和选择都在同一个对象身上。
如果不想每次都都磁盘,可需要缓存模板,设定 options.filename 即可。例如:
var ejs = require(\'../\') , fs = require(\'fs\') , path = __dirname + \'/functions.ejs\' , str = fs.readFileSync(path, \'utf8\'); var users = []; users.push({ name: \'Tobi\', age: 2, species: \'ferret\' }) users.push({ name: \'Loki\', age: 2, species: \'ferret\' }) users.push({ name: \'Jane\', age: 6, species: \'ferret\' }) var ret = ejs.render(str, { users: users, filename: path }); console.log(ret);
inculde 指令
而且,如果要如
<ul> <% users.forEach(function(user){ %> <% include user/show %> <% }) %> </ul>
般插入公共模板,也就是引入文件,必须要设置 filename 选项才能启动 include 特性,不然 include 无从知晓所在目录。
模板:
<h1>Users</h1> <% function user(user) { %> <li><strong><%= user.name %></strong> is a <%= user.age %> year old <%= user.species %>.</li> <% } %> <ul> <% users.map(user) %> </ul>
EJS 支持编译模板。经过模板编译后就没有 IO 操作,会非常快,而且可以公用本地变量。下面例子 user/show 忽略 ejs 扩展名:
<ul> <% users.forEach(function(user){ %> <% include user/show %> <% }) %> </ul>
var ejs = require(\'ejs\'); ejs.open = \'{{\'; ejs.close = \'}}\';
ejs.filters.last = function(obj) { return obj[obj.length - 1]; };
<p><%=: users | last %></p>
<html> <head> <script src=\"../ejs.js\"></script> <script id=\"users\" type=\"text/template\"> <% if (names.length) { %> <ul> <% names.forEach(function(name){ %> <li><%= name %></li> <% }) %> </ul> <% } %> </script> <script> onload = function(){ var users = document.getElementById(\'users\').innerHTML; var names = [\'loki\', \'tobi\', \'jane\']; var html = ejs.render(users, { names: names }); document.body.innerHTML = html; } </script> </head> <body> </body> </html>
对了,有网友爆料说,jQ 大神 John 若干年前写过 20 行的模板,汗颜,与 EJS 相似但短小精悍!
简单实用的js模板引擎
不足 50 行的 js 模板引擎,支持各种 js 语法:
<script id=\"test_list\" type=\"text/html\"> <%= for(var i = 0, l = p.list.length; i < l; i++){ var stu = p.list[i]; =%> <tr> <td<%=if(i==0){=%> class=\"first\"<%=}=%>><%==stu.name=%></td> <td><%==stu.age=%></td> <td><%==(stu.address || \'\')=%></td> <tr> <%= } =%> </script>
“<%= xxx =%>”内是 js 逻辑代码,“<%== xxx =%>”内是直接输出的变量,类似 php 的 echo 的作用。“p”是调用下面 build 方法时的 k-v 对象参数,也可以在调用 “new JTemp” 时设置成别的参数名
调用:
$(function(){ var temp = new JTemp(\'test_list\'), html = temp.build( {list:[ {name:\'张三\', age:13, address:\'北京\'}, {name:\'李四\', age:17, address:\'天津\'}, {name:\'王五\', age:13} ]}); $(\'table\').html(html); });
上面的 temp 生成以后,可以多次调用 build 方法,生成 html。以下是模板引擎的代码:
var JTemp = function(){ function Temp(htmlId, p){ p = p || {};//配置信息,大部分情况可以缺省 this.htmlId = htmlId; this.fun; this.oName = p.oName || \'p\'; this.TEMP_S = p.tempS || \'<%=\'; this.TEMP_E = p.tempE || \'=%>\'; this.getFun(); } Temp.prototype = { getFun : function(){ var _ = this, str = $(\'#\' + _.htmlId).html(); if(!str) _.err(\'error: no temp!!\'); var str_ = \'var \' + _.oName + \'=this,f=\\\'\\\';\', s = str.indexOf(_.TEMP_S), e = -1, p, sl = _.TEMP_S.length, el = _.TEMP_E.length; for(;s >= 0;){ e = str.indexOf(_.TEMP_E); if(e < s) alert(\':( ERROR!!\'); str_ += \'f+=\\\'\' + str.substring(0, s) + \'\\\';\'; p = _.trim(str.substring(s+sl, e)); if(p.indexOf(\'=\') !== 0){//js语句 str_ += p; }else{//普通语句 str_ += \'f+=\' + p.substring(1) + \';\'; } str = str.substring(e + el); s = str.indexOf(_.TEMP_S); } str_ += \'f+=\\\'\' + str + \'\\\';\'; str_ = str_.replace(/\\n/g, \'\');//处理换行 var fs = str_ + \'return f;\'; this.fun = Function(fs); }, build : function(p){ return this.fun.call(p); }, err : function(s){ alert(s); }, trim : function(s){ return s.trim?s.trim():s.replace(/(^\\s*)|(\\s*$)/g,\"\"); } }; return Temp; }();
核心是将模板代码转变成了一个拼接字符串的 function,每次拿数据 call 这个 function。
因为主要是给手机(webkit)用的,所以没有考虑字符串拼接的效率问题,如果需要给 IE 使用,最好将字符串拼接方法改为 Array.push() 的形式。
ejs模板布局 layout
1. 如果不愿意使用默认的layout.ejs,可自行指定。例如:
res.render(\"index\",{\"title\":\"test\",\"layout\":\"main\"}); // 或 res.render(\"index\",{\"title\":\"test\",\"layout\":\"main.ejs\"});
2. 如果不愿意使用layout,则可以设置layout为false,例如:
res.render(\"index\",{\"layout\":false});
3. 如果不想每个请求都单独设置一次。可以使用全局设置:
app.set(\"view options\",{ \"layout\":false });
4. ejs 里,默认的闭合标记是 <% .. %>,我们也可以定义自己的标签。例如:
app.set(\"view options\",{ \"open\":\"{{\", \"close\":\"}}\" });
5. 局部布局
在web应用中,经常会需要重复显示某个内容,例如:用户评论功能,需要重复显示出每一条用户的评论,这个时候,我们可以通过循环来实现。但是也可以使用【局部模版】( partial)来实现。例如:
首先我们建一个局部的模版 ./views/comment.ejs:
<div class=\"comment_item\"> <div class=\"comment_user\"><%=comment.user%></div> <div class=\"comment_content\"><%=comment.content%></div> </div>
注意:这里是 comment.xxxx
然后在./views/index.ejs中,通过partial调用comment
this is <%=title%>! <br/> <%- partial(\"comment\", comments)%>
注意:这里是 partial(\"comment.ejs\", comments); <-- 单词要用复数。
最后是在router中,调用index.ejs。
app.get(\"/\",function(req,res){ res.render(\"index\",{\"title\":\"test\",\"layout\":false,\"comments\":[ {\"user\":\"gainover\",\"content\":\"test1\"}, {\"user\":\"zongzi\",\"content\":\"test2\"}, {\"user\":\"maomao\",\"content\":\"test3\"} ]}); });
注意:代码里的 comments 和 index.ejs的 comments变量名称一致,而partial所调用的comment.ejs中,则采用 comment 的单数形式。
在列表显示时,我们通常会遇到的场景是,对第一个元素或者最后一个元素加以特殊显示。在partial中,我们可以通过express内置的变量来判断当前对象是否是第一个元素或者最后一个元素,例如:
<div class=\"comment_item<%if(firstInCollection){%> firtitem <%}%>\"> <div class=\"comment_user\"><%=comment.user%></div> : <div class=\"comment_content\"><%=comment.content%></div> </div>
这样第一条评论的 class 里就会多一个firstitem。
类似的内置变量还有:
(1)firstInCollection 如果是数组的第一个元素,则为true
(2)indexInCollection 当前元素在数组里的索引
(3)lastInCollection 如果是数组的最后一个元素,则为true
(4)collectionLength 数组的长度
最后是partial调用模版时的路径查找问题:
(1)partial(\"edit\") 会查找同目录下的edit.ejs文件。
(2)partial(\"../message\") 会查找上一级目录的message.ejs文件。
(3)partial(\"users\") 会查找 users.ejs文件,如果不存在users.ejs, 则会查找 /users/index.ejs文件。
(4)<%= users %> 会对内容进行转义,想不转义,可以用 <%- users %>
本文地址:https://www.stayed.cn/item/5025
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我