2010-08-30 70 views
11

我有一个基本的Express服务器:如何将内容从模板传递到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'} 
    }); 
}); 

有了一个基本的玉布局:

// 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或简单的实例变量。)

+0

行之有效虽然它是一个基于DocPad一个CMS,也许你会发现它有用,因为它已经内置布局和玉的支持。 https://github.com/balupton/docpad – balupton 2011-09-20 10:52:58

回答

19

通过使用上面关于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; 
     } 
    }; 
} 

所以调用创建()与get()和设置就可以了()方法返回一个对象,即获取和设置闭包变量。

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

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

由于动态助手的价值是调用其功能,在您的视图和模板的结果,PAGE_TITLE变量将与获得包装对象( )和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() 
     }); 
+0

我碰到过闭包最实际的用途之一! – 2012-08-08 06:15:16

+0

您是如何在视图中实际使用它的?我喜欢这个想法,但对我来说,set()函数永远不会被调用,并且get()始终为空。 – qodeninja 2012-10-11 21:52:56

0

Pass它在当地人:{some: 'Locals', pageTitle: 'Welcome!'}

+0

我没有从该模板中的“本地人”。我必须保留'{template path:page title}'的地图,并在渲染之前查看页面标题。必须有一种方法可以在模板本身的*内指定它。 – 2010-08-30 14:28:34

5

Express不具有“块”或不管他们叫的是,在轨道的先入为主的观念,但是你可以使用助手()和dynamicHelpers()来实现类似的组合http://expressjs.com/guide.html#app-helpers-obj-

虽然

+0

所以这个想法是添加一个动态助手,在请求中存储'pageTitle',然后布局可以读出?这听起来像一个好的解决方案。我甚至可以把它作为中间件包装起来并发布! – 2010-08-30 15:40:29

1

你可以通过使用这个小片段来做到这一点。

prop.js:

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

服务器。JS:

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

查看:

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

布局:

<%= prop.get('foo') %> 
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'); 
...

易pe。

0

对于快递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() 
相关问题