如何在Express中从模板传递内容到布局?

11

我有一个基本的Express服务器:

// server.js:
var Express = require('express');
app = Express.createServer();
app.configure(function(){
  app.set('views', Path.join(__dirname, 'views'));
  app.set('view engine', 'jade');
  app.set('view options');
});
app.get('/', function (request, response) {
  response.render('welcome', {
    locals: {some: 'Locals'}
  });
});

使用基本的jade布局:

// views/layout.jade:
!!! 5
html(lang='en')
  head
    title= pageTitle
  body
    h1= pageTitle
    aside(id="sidebar")= sidebarContent
    #content
      #{body}

还有一个简单的页面:

# views/welcome.jade:
// How do I pass pageTitle and sidebarContent out to the layout from here?
p
  Welcome to my fine site!

(在Rails中,这可能是像content_for或一个简单的实例变量。)


虽然它是基于DocPad的CMS,但也许你会发现它很有用,因为它内置了对布局和jade的支持。https://github.com/balupton/docpad - balupton
6个回答

20

使用关于dynamicHelpers的上面的提示和闭包的魔力,我发现了一种相当优雅的解决方案,可以在不涉及请求对象的情况下工作。技巧是将页面标题变量封装在一个提供get()和set()函数的闭包中,并将该包装器对象作为page_title动态助手的结果。

创建一个property.js文件:

exports.create = function () {
    var value = null;
    return {
        get: function () {
           return value;
        },
        set: function (new_value) {
           value = new_value;
        }
    };
}

调用create()函数会返回一个对象,该对象具有get()和set()方法,这些方法可以获取和设置闭包变量。

然后,在您的应用程序设置代码中:

    var property = require("./property.js");
    app.dynamicHelpers ({
        page_title: function () {
         return property.create ();
        }
    });

由于动态帮助器的值是调用其函数的结果,在您的视图和模板中,page_title变量将是具有get()和set()函数的包装对象。

在您的视图中,您可以这样说:

- page_title.set ("my specific page title");

然后在您的布局中:

title= page_title.get()
为了更加简化这个过程,将下面的内容添加到property.js文件中:
exports.creator = function () {
    return function () {
        return exports.create();
    };
}

让您将动态助手声明块简化为以下形式:

        var property = require("./property.js");
        app.dynamicHelpers ({
            page_title: property.creator()
        });

我遇到的闭包最实用的用途之一! - Mark Nguyen
你实际上是如何在视图中使用它的?我喜欢这个想法,但对我来说,set()函数从未被调用,而get()始终为空。 - qodeninja

5
Express没有像Rails中的“块”那样的预设概念,但你可以使用helpers()和dynamicHelpers()的组合来实现类似的功能。详见http://expressjs.com/guide.html#app-helpers-obj-
传递的本地变量可在布局和页面视图中使用。

那么,想法是添加一个动态助手,在请求中存储 pageTitle,然后布局可以读取它?这听起来像是一个很好的解决方案。我甚至可以将其包装成中间件并发布! - James A. Rosen

2

layout.jade

# the following function is a safe getter/setter for locals
- function pagevar(key, value) { var undef; return (value===undef) ? locals[key] || null : locals[key] = value; }
block config
  #intended as a non-rendered block so that locals can be overridden.
  # put your defaults here... - use append in the child view
!!!
html
  head
    title=pagevar('title')
    meta(name='description',content=pagevar('description'))
...

page.jade

append config
  - locals.title = 'override';
  - locals.description = 'override 2';
  - pagevars('somekey', 'some value');
...

轻松愉快。

1

您可以使用这个小片段来实现。

prop.js:

var hash = {};
module.exports = function() {
    return {
        set: function(key, val) { hash[key] = val },
        get: function(key) { return hash[key] }
    };
};

server.js:

app.dynamicHelpers({ prop: require(__dirname + '/views/helpers/prop') });

查看:

<% prop.set('foo', 'bar') %>

布局:

<%= prop.get('foo') %>

0

对于 Express 3 模板不可知,与 express-partials 配合良好

app.use (req, res, next)->
  req.locals = {} unless req.locals

  res.locals.content_for = (k, v = null)->
    if !v
      req.locals[k]
    else
      req.locals[k] = v

  next()

0
将其传递到本地变量中:{some: 'Locals', pageTitle: '欢迎!'}


我在模板内部没有“locals”。我必须保持一个映射表格,其中包含{模板路径:页面标题},并在渲染之前查找页面标题。一定有一种方法可以从模板本身中指定它。 - James A. Rosen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接