nodejs express 框架解密5-视图

 本文档是基于express 3.4.6 的

在我们的代码中,渲染模板大致是这样写的

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

这个req,res 函数其实是经过了中间件middleware.js 处理后的,我们在前面提到过。

req,res的原型分别为 app.request 和app.response

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

而 app.request 和app.response,本身也是具有app的属性的。

//设置app 的request对象的原型为req,本身的属性为connect对象
app.request = { __proto__: req, app: app };
//设置app的response对象原型为res ,本身的属性为connect对象
app.response = { __proto__: res, app: app };

注意这里的这个app属性

打开response.js 文件,我们看看res.render方法

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);
};

可以看到:

, 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);

后面就去调用具体的模板引擎了。

posted @ 2013-12-19 15:55  yupeng  阅读(8426)  评论(0编辑  收藏  举报