查找布局并在express / ejs中的多个路径中包含文件

时间:2014-05-08 16:07:10

标签: node.js express ejs

我正在使用ejs作为模板引擎构建基于express的节点应用程序。

为了支持网站的不同外观我想将文件放在名为base holding vanilla stuff的文件夹中,并为每个样式/主题/客户端添加一个叠加层。我希望系统首先在叠加层中查找文件,并且只有在未找到时才使用基础中的文件。

对于像图像和css文件这样的静态内容,这可以使用静态中间件两次,首先是覆盖,然后是基础。

我想对通过ejs呈现的模板执行相同的操作。我找到了:

Multiple View paths on Node.js + Express

只要我调用简单的ejs视图,那个线程中提供的BananaAcids答案几乎适用于我。如果我想使用布局或包含它,则会因覆盖视图而分解,因为基本目录现在已覆盖,并且不再找到与基础相同的布局。

以下是一个简化的例子。

文件库/布局/ root.ejs:

<!DOCTYPE html>
<html lang="en">
  <body>
    <!-- Main content of pages using this layout goes here -->
    <%- body %>
  </body>
</html>

文件库/ index.ejs:

<% layout('layouts/root') -%>
<p>
    A page in base using the root layout
</p>

文件覆盖/ index.ejs:

<% layout('layouts/root') -%>
<p>
    Totally different page in the overlay.
</p>

使用BananaAcids方法并将两个路径设置为view-sources express / ejs现在可以正确地将overlay / index.ejs定位为要渲染的视图,但由于我没有覆盖布局/ root它失败,因为生成的文件覆盖/布局/ root.ejs不存在。

有没有办法将我的方法进一步修改为ejs,以便我可以帮助它在base / layout / root.ejs中找到这个文件?

感谢您阅读本文以及您已经花费的任何脑力循环。

2 个答案:

答案 0 :(得分:0)

以下是我用来修补Express(4.x)以添加布局支持的内容:

/*
   Usage:
     Set a global/default layout with:
        app.set('view layout', 'foo');
     Set a layout per-render (overrides global layout) with:
        res.render('foo', { layout: 'bar' });
     Or disable a layout if a global layout is set with:
        res.render('foo', { layout: false });
     If no layout is provided using either of the above methods,
     then the view will be rendered as-is like normal.

     Inside your layout, the variable `body` holds the rendered partial/child view.

   Installation:
     Call `mpResponse();` before doing `require('express');` in your application.
*/

function mpResponse() {
  var expressResponse = require('express/lib/response'),
      expressResRender = expressResponse.render;
  expressResponse.render = function(view, options, fn) {
    options = options || {};
    var self = this,
        req = this.req,
        app = req.app,
        layout,
        cb;

    // support callback function as second arg
    if (typeof options === 'function')
      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);
    };

    if (typeof options.layout === 'string')
      layout = options.layout;
    else if (options.layout !== false
             && typeof app.get('view layout') === 'string')
      layout = app.get('view layout');

    if (layout) {
      cb = function(err, str) {
        if (err) return req.next(err);
        options.body = str;
        expressResRender.call(self, layout, options, fn);
      };
    } else
      cb = fn;

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

答案 1 :(得分:0)

我修补了EJS以支持Express v.4.10中添加的多视图文件夹功能。您可以在此处找到待处理的拉取请求:https://github.com/mde/ejs/pull/120。如果你的项目仍然需要这个解决方案,你可以将我的fork作为EJS替换包含在你的package.json中:

public static StudentManager sm = new StudentManager(); // GET: Student public ActionResult Index() { return View(sm.sList); } public ActionResult Edit(int? id) { Students student = sm.sList.Where(s => s.Sid == id).First(); return View(student); } [HttpPost] public ActionResult Edit(Students s) { sm.Edit(s); return RedirectToAction("Index"); }

..或者你加一个拉请求,希望很快就会被接受。