nodejs express 框架解密5-視圖

 本文檔是基於express 3.4.6 的express

在咱們的代碼中,渲染模板大體是這樣寫的app

exports.index = function(req, res){
  res.render('index', { title: 'Express' });
};

這個req,res 函數實際上是通過了中間件middleware.js 處理後的,咱們在前面提到過。less

req,res的原型分別爲 app.request 和app.responseide

req.__proto__ = app.request;
res.__proto__ = app.response;函數

而 app.request 和app.response,自己也是具備app的屬性的。ui

//設置app 的request對象的原型爲req,自己的屬性爲connect對象
app.request = { __proto__: req, app: app };
//設置app的response對象原型爲res ,自己的屬性爲connect對象
app.response = { __proto__: res, app: app };this

注意這裏的這個app屬性spa

打開response.js 文件,咱們看看res.render方法prototype

res.render = function(view, options, fn){
  var self = this
    , options = options || {}
    , req = this.req
    , app = req.app;

  // support callback function as second arg
  if ('function' == typeof options) {
    fn = options, options = {};
  }

  // merge res.locals
  options._locals = self.locals;

  // default callback to respond
  fn = fn || function(err, str){
    if (err) return req.next(err);
    self.send(str);
  };

  // render
  app.render(view, options, fn);
};

能夠看到:code

, req = this.req
, app = req.app;

這裏的 req = this.req,實際上是中間件 裏面的  res.req = req;

第二句直接將app帶進來了,最後咱們執行了app.render方法,它調用了application.js 中得這個方法:

app.render = function(name, options, fn){
  var opts = {}
    , cache = this.cache
    , engines = this.engines
    , view;

  // support callback function as second arg
  if ('function' == typeof options) {
    fn = options, options = {};
  }

  // merge app.locals
  utils.merge(opts, this.locals);

  // merge options._locals
  if (options._locals) utils.merge(opts, options._locals);

  // merge options
  utils.merge(opts, options);

  // set .cache unless explicitly provided
  opts.cache = null == opts.cache
    ? this.enabled('view cache')
    : opts.cache;

  // primed cache
  if (opts.cache) view = cache[name];

  // view
  if (!view) {
    view = new (this.get('view'))(name, {
      defaultEngine: this.get('view engine'),
      root: this.get('views'),
      engines: engines
    });

    if (!view.path) {
      var err = new Error('Failed to lookup view "' + name + '"');
      err.view = view;
      return fn(err);
    }

    // prime the cache
    if (opts.cache) cache[name] = view;
  }

  // render
  try {
    view.render(opts, fn);
  } catch (err) {
    fn(err);
  }
};

能夠看到它調用了視圖類:

 view = new (this.get('view'))(name, {
      defaultEngine: this.get('view engine'),
      root: this.get('views'),
      engines: engines
    });

最後調用了視圖的render方法。 view.render(opts, fn);

視圖的這個方法是:

View.prototype.render = function(options, fn){
  this.engine(this.path, options, fn);
};
function View(name, options) {
  options = options || {};
  this.name = name;
  this.root = options.root;
  var engines = options.engines;
  this.defaultEngine = options.defaultEngine;
  var ext = this.ext = extname(name);
  if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
  if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
  this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
  this.path = this.lookup(name);
}

引擎require了一個方法

this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);

後面就去調用具體的模板引擎了。

相關文章
相關標籤/搜索