如何使用Express / Node.JS创build在所有视图中可访问的全局variables?

好的,我已经使用Jekyll创build了一个博客,您可以在_config.yml文件中定义可在所有模板/布局中访问的variables。 我正在使用Node.JS / Express与EJS模板和ejs-locals (用于partials / layouts)。我正在寻找类似于像_config.yml中find的site.title这样的全局variables,如果有人熟悉Jekyll 。我有像网站的标题,(而不是页面标题),作者/公司名称,在我的所有网页上保持相同的variables。

这是我目前正在做的一个例子。

 exports.index = function(req, res){ res.render('index', { siteTitle: 'My Website Title', pageTitle: 'The Root Splash Page', author: 'Cory Gross', description: 'My app description', indexSpecificData: someData }); }; exports.home = function (req, res) { res.render('home', { siteTitle: 'My Website Title', pageTitle: 'The Home Page', author: 'Cory Gross', description: 'My app description', homeSpecificData: someOtherData }); }; 

我希望能够在一个地方定义像我的网站的标题,描述,作者等variables,并通过EJS在我的布局/模板中访问它们,而不必将它们作为选项传递给res.render 。 有没有办法做到这一点,仍然允许我传递其他variables特定于每个页面?

在有机会学习Express 3 API Reference之后,我发现了一些我正在寻找的东西。 具体来说, app.locals的条目,然后再往下res.locals举行我需要的答案。

我发现自己的functionapp.locals接受一个对象,并将其全部属性存储为应用程序的全局variables。 这些全局variables作为局部variables传递给每个视图。 然而, res.locals函数的作用范围是这个请求,因此响应局部variables只能在特定请求/响应期间呈现的视图访问。

所以对于我的情况在我的app.js我所做的是添加:

 app.locals({ site: { title: 'ExpressBootstrapEJS', description: 'A boilerplate for a simple web application with a Node.JS and Express backend, with an EJS template with using Twitter Bootstrap.' }, author: { name: 'Cory Gross', contact: 'CoryG89@gmail.com' } }); 

然后所有这些variables都可以在我的意见作为site.titlesite.descriptionauthor.nameauthor.contact

我也可以使用res.locals为每个请求的响应定义局部variables,或者简单地像render调用中的options参数那样传递像页面标题一样的variables。

编辑:这种方法不会让你在你的中间件中使用这些当地人。 我实际上是在Pickels在下面的评论中提到的。 在这种情况下,您将需要创build一个中间件function在他的替代(和赞赏)的答案。 您的中间件function需要将它们添加到每个响应的res.locals中,然后再调用。 这个中间件function将需要放在任何其他需要使用这些本地中间件的中间件之上。

编辑:通过app.localsres.locals声明当地人之间的另一个区别是与app.localsvariables设置一个单一的时间,并坚持贯穿整个应用程序的生活。 当您在中间件中设置了res.locals本地res.locals时,每当您收到请求时都会设置这些文件。 你应该更喜欢通过app.locals设置全局variables,除非值取决于传入中间件的请求variables。 如果这个值没有改变,那么它会在app.locals设置一次效率app.locals

您可以通过将它们添加到通用中间件中的本地对象来实现此目的。

 app.use(function (req, res, next) { res.locals = { siteTitle: "My Website's Title", pageTitle: "The Home Page", author: "Cory Gross", description: "My app's description", }; next(); }); 

当地人也是一个扩大当地人对象而不是覆盖它的function。 所以下面的工作也是如此

 res.locals({ siteTitle: "My Website's Title", pageTitle: "The Home Page", author: "Cory Gross", description: "My app's description", }); 

完整的例子

 var app = express(); var middleware = { render: function (view) { return function (req, res, next) { res.render(view); } }, globalLocals: function (req, res, next) { res.locals({ siteTitle: "My Website's Title", pageTitle: "The Root Splash Page", author: "Cory Gross", description: "My app's description", }); next(); }, index: function (req, res, next) { res.locals({ indexSpecificData: someData }); next(); } }; app.use(middleware.globalLocals); app.get('/', middleware.index, middleware.render('home')); app.get('/products', middleware.products, middleware.render('products')); 

我还添加了一个通用的渲染中间件。 这样你就不必为每条路由添加res.render,这意味着你有更好的代码重用。 一旦你下了可重用的中间件路线,你会注意到你将会有很多积木,这将加速发展。

对于Express 4.0,我发现使用应用程序级别variables的工作方式稍有不同,Cory的答案对我来说不起作用。

从文档: http : //expressjs.com/en/api.html#app.locals

我发现你可以在应用程序中声明一个全局variables

 app.locals 

例如

 app.locals.baseUrl = "http://www.google.com" 

然后在您的应用程序中,您可以访问这些variables,在您的快递中间件中,您可以在req对象中访问它们

 req.app.locals.baseUrl 

例如

 console.log(req.app.locals.baseUrl) //prints out http://www.google.com 

在你的app.js中,你需要添加这样的东西

 global.myvar = 100; 

现在,在你想要使用这个variables的所有文件中,你可以像myvar那样访问它

一种方法是通过更新app.js该app的app.localsvariables

通过以下设置

 var app = express(); app.locals.appName = "DRC on FHIR"; 

获取/访问

 app.listen(3000, function () { console.log('[' + app.locals.appName + '] => app listening on port 3001!'); }); 

从@RamRovi示例的屏幕截图进行细化,略有增强。

在这里输入图像说明

你也可以使用“全球”

例:

声明如下:

  app.use(function(req,res,next){ global.site_url = req.headers.host; // hostname = 'localhost:8080' next(); }); 

像这样使用:在任何视图或ejs文件<%console.log(site_url); %>

在js文件console.log(site_url);

我为了避免受到污染的全球范围所做的是创build一个脚本,我可以将其包含在任何地方。

 // my-script.js const ActionsOverTime = require('@bigteam/node-aot').ActionsOverTime; const config = require('../../config/config').actionsOverTime; let aotInstance; (function () { if (!aotInstance) { console.log('Create new aot instance'); aotInstance = ActionsOverTime.createActionOverTimeEmitter(config); } })(); exports = aotInstance; 

这样做只会创build一个新的实例,并在文件所在的位置共享。 我不确定是因为variables被caching还是因为应用程序的内部引用机制(可能包括caching)。 有关节点如何解决这个问题的任何意见将是伟大的。

也许还可以阅读这个获得如何工作的要点: http : //fredkschott.com/post/2014/06/require-and-the-module-system/