express传入模板引擎变量的源码分析
发布于 6 年前 作者 2015308200114dujiawei 2678 次浏览 来自 分享

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)设置的模板引擎进行渲染。 掘金连接:https://juejin.im/post/5cd0f948e51d456e2d69a828 引用:

1.《node.js实战》图片

​ ​2.express.源码

回到顶部