在Express中使用自定义视图模板引擎

众所周知,Express阵营中视图模板大多是Jade或则ejs,使用起来简单高效。既然是模板,那就需要规定好模板语言的格式,比如jade的缩进格式,ejs的<% %>

那么,什么时候需要自定义视图模板引擎呢?对了,就是当模板语言是自定义的时候。不幸,我们在项目中就遇到了这种需求,所以需要自己实现一个模板引擎。所幸,在Express中使用一个自定义视图引擎是非常简单。往下看。

相关API:

app.engine(ext, callback)
app.set(name, value)

这里简单概括下:

  • 使用app.engine(ext, callback) 创建视图引擎,其中ext是模板文件的后缀名, callback的函数签名为function(filePath, options, callback),其中

    • filePath是模板文件的路径
    • options是数据对象,常用来替换模板中的占位符
    • callback回调的签名是function(err, renderedHtml)
  • 使用app.set('view engine', 'ext')配置Application Settings,注册自己的视图引擎,其中ext是模板文件的后缀名

Show Me The Code

先准备好一个Express的骨架工程,删除关于view engine的配置

删除app.js中下面的代码(如果有,或者jade):

1
2
3
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

替换为自定义的视图引擎:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 自定义 视图引擎
var fs = require('fs'); // 读取模板文件内容时,需要fs模块
// 自定义模板文件后缀名为.abc
app.engine('abc', function(filePath, options, callback) {
// 定义我们自己的视图引擎
fs.readFile(filePath, function(err, content) {
if (err) {
return callback(new Error(err));
}
// 这是一个非常简单实现。。。
var rendered = content.toString()
.replace('#name#', options.name)
.replace('#age#', options.age);
return callback(null, r endered);
})
});
// 指定视图目录
app.set('views', path.join(__dirname, 'views'));
// 注册自定义模板引擎
app.set('view engine', 'abc');

注册路由:

1
2
3
4
5
6
app.use('/', function(req, res, next) {
res.render('index.abc', {
name: 'le0zh',
age: 31
});
});

在views文件夹中添模板文件index.abc:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>自定义模板引擎测试</title>
</head>
<body>
<h3>自定义模板引擎测试</h3>
<p>姓名: #name#</p>
<p>年龄: #age#</p>
</body>
</html>

完成之后,启动Express:

1
node app.js

使用浏览器访问,可以看到渲染后的页面啦。

更进一步

上面的例子中,我们的模板引擎非常简单,当它复杂起来时,一大坨的代码在app.js中,影响阅读。
下面我们模块化,将模板引擎提出来,新建一个myViewEngine.js文件,把引擎的逻辑放进去:

1
2
3
4
5
6
7
var fs = require('fs');
var myViewEngine = function(filePath, options, callback) {
// ...具体略
};
module.exports = myViewEngine;

现在,在app.js中只需要:

1
2
3
4
5
6
7
var myViewEngine = require('./myViewEngine');
app.engine('abc', myViewEngine);
// 指定视图目录
app.set('views', path.join(__dirname, 'views'));
// 注册自定义模板引擎
app.set('view engine', 'abc');

剩下的工作,就是丰富myViewEngine.js的功能了。