Node 开源模板的选择很多,但推荐像我这样的老人去用 EJS,有 Classic ASP/PHP/JSP 的经验用起 EJS 来的确可以很自然,也就是说,你能够在 <%...%> 块中安排 JavaScript 代码,利用最传统的方式 <%=输出变量%>(另外 <%-输出变量是不会对 & 等符号进行转义的)。安装 EJS 命令如下:
rush:bash;">
npm install ejs
JS
调用的
方法主要有两个:
Function
ejs.render(str,options);
// => str
实际上 EJS 可以游离于 Express 独立使用的,例如:
rush:js;">
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) { %>
<% names.forEach(function(name){ %>
- '><%= name %>
<% }) %>
<% } %>
names 成了本地变量。
选项参数
第二个参数是数据,一般是
一个对象。而这个对象又可以视作为选项,也就是说数据和选择都在同
一个对象身上。
如果不想每次都都磁盘,可需要缓存模板,设定 options.filename 即可。例如:
rush:js;">
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',species: 'ferret' })
users.push({ name: 'Jane',age: 6,species: 'ferret' })
var ret = ejs.render(str,{
users: users,filename: path
});
console.log(ret);
inculde 指令
而且,如果要如
rush:js;">
<% users.forEach(function(user){ %>
<% include user/show %>
<% }) %>
般插入公共模板,也就是引入文件,必须要设置 filename 选项才能启动 include 特性,不然 include 无从知晓所在目录。
模板:
rush:js;">
Users
<% function user(user) { %>
<%= user.name %>
is a <%= user.age %> year old <%= user.species %>.
<% } %>
EJS 支持编译模板。经过模板编译后就没有 IO 操作,会非常快,而且可以公用本地变量。下面例子 user/show 忽略 ejs 扩展名:
rush:js;">
<% users.forEach(function(user){ %>
<% include user/show %>
<% }) %>
自定义 CLOSE TOKEN
如果打算使用
{{= title }}
般非 <%%>标识,也可以
自定义的。
rush:js;">
var ejs = require('ejs');
ejs.open = '{{';
ejs.close = '}}';
格式化
输出也可以哦。
rush:js;">
ejs.filters.last = function(obj) {
return obj[obj.length - 1];
};
调用:
rush:js;">
<%=: users | last %>
EJS 也
支持浏览器环境。
rush:js;">
不知道 EJS 能否
输出多层 JSON 对象呢?
对了,有网友爆料说,jQ 大神 John 若干年前写过 20 行的模板,汗颜,与 EJS 相似但短小精悍!
简单实用的js模板引擎
不足 50 行的 js 模板引擎,
支持各种 js 语法:
rush:js;">
“<%= xxx =%>”内是 js 逻辑代码,“<%== xxx =%>”内是直接输出的变量,类似 PHP 的 echo 的作用。“p”是调用下面 build 方法时的 k-v 对象参数,也可以在调用 “new JTemp” 时设置成别的参数名
调用:
rush:js;">
$(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。以下是模板引擎的代码:
rush:js;">
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,可自行指定。例如:
rush:js;">
res.render("index",{"title":"test","layout":"main"});
// 或
res.render("index","layout":"main.ejs"});
2. 如果不愿意使用layout,则可以设置layout为false,例如:
rush:js;">
res.render("index",{"layout":false});
3. 如果不想每个请求都单独设置一次。可以使用全局设置:
rush:js;">
app.set("view options",{
"layout":false
});
4. ejs 里,默认的闭合标记是 <% .. %>,我们也可以定义自己的标签。例如:
rush:js;">
app.set("view options",{
"open":"{{","close":"}}"
});
5. 局部布局
在web应用中,经常会需要重复显示某个内容,例如:用户评论功能,需要重复显示出每一条用户的评论,这个时候,我们可以通过循环来实现。但是也可以使用【局部模版】( partial)来实现。例如:
首先我们建一个局部的模版 ./views/comment.ejs:
rush:js;">
rush:js;">
app.get("/",function(req,res){
res.render("index","layout":false,"comments":[
{"user":"gainover","content":"test1"},{"user":"zongzi","content":"test2"},{"user":"maomao","content":"test3"}
]});
});