express中为模板传入变量的时候可以通过:
1.res.render的options:
通过向res.render函数传入optinos:res.render(目标模板名,{user:'djw'});
在EJS模版中通过<%=user%>使用变量
2.res.locals:
在res.locas对象上直接赋值:res.locals.user = 'djw'
3.app.locals
在res.locas对象上直接赋值:res.locals.user = 'djw'
4.app.set
通过向app.set函数传入变量名称和值:app.set('user','djw');这种方式会向模板中传入一个程序级变量Settings,在EJS模板中通过<%=settings.user%>使用变量
res.render的opts 、res.locals、app.locals的优先级:
由于通过app.set设置的变量其实只挂在app.locals.settings上面的,所以不用考虑优先级设置。
为什么是这种优先级呢?
在调用res.render中会先把res.locals挂到res.render的options上①,然后调用app.render②:
res.render = function render(view, options, callback) {
var app = this.req.app;
var done = callback;
var opts = options || {};
var req = this.req;
var self = this;
// support callback function as second arg
if (typeof options === 'function') {
done = options;
opts = {};
}
// merge res.locals
opts._locals = self.locals; ①
// default callback to respond
done = done || function (err, str) {
if (err) return req.next(err);
self.send(str);
};
// render
app.render(view, opts, done); ②
};
在app.render创建renderOptions然后依次把app.locals,res.locals,res.render的optionsmerge到renderOptions上。
先看下merge的实现:
exports = module.exports = function(a, b){
if (a && b) {
for (var key in b) {
a[key] = b[key];
}
}
return a;
};
merge把b上的属性赋值到a上,所以后merge的会覆盖之前已存在的属性,例如:app.locals.user=‘djw’会先merge到renderOptions上,之后res.locals.user=‘kkp’会后覆盖掉已存在的user。这样就形成了res.render的options>res.locals>app.locals的优先级。
源码:
app.render = function render(name, options, callback) {
var cache = this.cache;
var done = callback;
var engines = this.engines;
var opts = options;
var renderOptions = {};
var view;
// support callback function as second arg
if (typeof options === 'function') {
done = options;
opts = {};
}
// merge app.locals
merge(renderOptions, this.locals);
// merge options._locals options._locals就是挂在的render的options上的res.locals
if (opts._locals) {
merge(renderOptions, opts._locals);
}
// merge options
merge(renderOptions, opts);
// set .cache unless explicitly provided
if (renderOptions.cache == null) {
renderOptions.cache = this.enabled('view cache');
}
// primed cache
if (renderOptions.cache) {
view = cache[name];
}
// view
if (!view) {
var View = this.get('view');
view = new View(name, {
defaultEngine: this.get('view engine'),
root: this.get('views'),
engines: engines
});
if (!view.path) {
var dirs = Array.isArray(view.root) && view.root.length > 1
? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
: 'directory "' + view.root + '"'
var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
err.view = view;
return done(err);
}
// prime the cache
if (renderOptions.cache) {
cache[name] = view;
}
}
// render
tryRender(view, renderOptions, done);
};
之后tryRender通过app.set('view',fn)设置的模板引擎进行渲染。
引用:
1.《node.js实战》图片
2.express.源码