如何使用 Express/Node.JS 创建可在所有视图中访问的全局变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16452123/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create global variables accessible in all views using Express / Node.JS?
提问by Cory Gross
Ok, so I have built a blog using Jekylland you can define variables in a file _config.ymlwhich are accessible in all of the templates/layouts. I am currently using Node.JS/ Expresswith EJStemplates and ejs-locals(for partials/layouts. I am looking to do something similar to the global variables like site.titlethat are found in _config.ymlif anyone is familiar with Jekyll. I have variables like the site's title, (rather than page title), author/company name, which stay the same on all of my pages.
好的,所以我使用Jekyll建立了一个博客,您可以在一个文件中定义变量,_config.yml这些变量可以在所有模板/布局中访问。我目前使用的Node.js/快递与EJS模板和EJS本地人(用于谐音/布局。我希望做类似像全局变量的东西site.title,在被发现_config.yml如果有人熟悉化身。我有这样的变量网站的标题(而不是页面标题)、作者/公司名称,在我的所有页面上都保持不变。
Here is an example of what I am currently doing.:
这是我目前正在做的一个例子。:
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
});
};
I would like to be able to define variables like my site's title, description, author, etc in one place and have them accessible in my layouts/templates through EJS without having to pass them as options to each call to res.render. Is there a way to do this and still allow me to pass in other variables specific to each page?
我希望能够在一个地方定义我的网站标题、描述、作者等变量,并通过 EJS 在我的布局/模板中访问它们,而不必将它们作为选项传递给res.render. 有没有办法做到这一点,并且仍然允许我传入特定于每个页面的其他变量?
回答by Cory Gross
After having a chance to study the Express 3 API Referencea bit more I discovered what I was looking for. Specifically the entries for app.localsand then a bit farther down res.localsheld the answers I needed.
在有机会进一步研究Express 3 API Reference之后,我发现了我想要的东西。具体来说app.locals,然后再往下一点的条目包含res.locals了我需要的答案。
I discovered for myself that the function app.localstakes an object and stores all of its properties as global variables scoped to the application. These globals are passed as local variables to each view. The function res.locals, however, is scoped to the request and thus, response local variables are accessible only to the view(s) rendered during that particular request/response.
我自己发现该函数app.locals接受一个对象并将其所有属性存储为应用程序范围内的全局变量。这些全局变量作为局部变量传递给每个视图。res.locals然而,该函数的作用域是请求,因此,响应局部变量只能被在该特定请求/响应期间呈现的视图访问。
So for my case in my app.jswhat I did was add:
所以对于我的情况,我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: '[email protected]'
}
});
Then all of these variables are accessible in my views as site.title, site.description, author.name, author.contact.
然后所有这些变量都可以在我的视图中访问为site.title, site.description, author.name, author.contact。
I could also define local variables for each response to a request with res.locals, or simply pass variables like the page's title in as the optionsparameter in the rendercall.
我还可以使用 为对请求的每个响应定义局部变量res.locals,或者简单地将页面标题等变量作为调用中的options参数传递render。
EDIT:This method will notallow you to use these locals in your middleware. I actually did run into this as Pickels suggests in the comment below. In this case you will need to create a middleware function as such in his alternative (and appreciated) answer. Your middleware function will need to add them to res.localsfor each response and then call next. This middleware function will need to be placed above any other middleware which needs to use these locals.
编辑:此方法将不会让你在你的中间件使用这些本地人。正如 Pickels 在下面的评论中所建议的那样,我确实遇到了这个问题。在这种情况下,您将需要在他的替代(和赞赏)答案中创建一个中间件功能。您的中间件函数需要res.locals为每个响应添加它们,然后调用next. 这个中间件函数需要放置在需要使用这些本地变量的任何其他中间件之上。
EDIT:Another difference between declaring locals via app.localsand res.localsis that with app.localsthe variables are set a single time and persist throughout the life of the application. When you set locals with res.localsin your middleware, these are set everytime you get a request. You should basically prefer setting globals via app.localsunless the value depends on the request reqvariable passed into the middleware. If the value doesn't change then it will be more efficient for it to be set just once in app.locals.
编辑:通过app.locals和声明本地变量之间的另一个区别res.locals是app.locals变量设置一次并在应用程序的整个生命周期中持续存在。当您res.locals在中间件中设置 locals 时,每次收到请求时都会设置这些。您基本上应该更喜欢通过设置全局变量,app.locals除非该值取决于req传递给中间件的请求变量。如果该值没有改变,那么在app.locals.
回答by Pickels
You can do this by adding them to the locals object in a general middleware.
您可以通过将它们添加到通用中间件中的 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();
});
Locals is also a function which will extend the locals object rather than overwriting it. So the following works as well
Locals 也是一个函数,它将扩展 locals 对象而不是覆盖它。所以以下也有效
res.locals({
siteTitle: "My Website's Title",
pageTitle: "The Home Page",
author: "Cory Gross",
description: "My app's description",
});
Full example
完整示例
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'));
I also added a generic render middleware. This way you don't have to add res.render to each route which means you have better code reuse. Once you go down the reusable middleware route you'll notice you will have lots of building blocks which will speed up development tremendously.
我还添加了一个通用渲染中间件。这样您就不必将 res.render 添加到每个路由,这意味着您可以更好地重用代码。一旦你沿着可重用的中间件路线走下去,你会注意到你将拥有大量的构建块,这将极大地加快开发速度。
回答by RamRovi
For Express 4.0 I found that using application level variables works a little differently & Cory's answer did not work for me.
对于 Express 4.0,我发现使用应用程序级变量的工作方式略有不同,Cory 的回答对我不起作用。
From the docs: http://expressjs.com/en/api.html#app.locals
来自文档:http: //expressjs.com/en/api.html#app.locals
I found that you could declare a global variable for the app in
我发现你可以为应用程序声明一个全局变量
app.locals
e.g
例如
app.locals.baseUrl = "http://www.google.com"
And then in your application you can access these variables & in your express middleware you can access them in the req object as
然后在您的应用程序中,您可以访问这些变量 & 在您的 express 中间件中,您可以在 req 对象中访问它们
req.app.locals.baseUrl
e.g.
例如
console.log(req.app.locals.baseUrl)
//prints out http://www.google.com
回答by Fernando Bustos
In your app.js you need add something like this
在你的 app.js 你需要添加这样的东西
global.myvar = 100;
Now, in all your files you want use this variable, you can just access it as myvar
现在,在你想要使用这个变量的所有文件中,你可以访问它 myvar
回答by Gajen Sunthara
One way to do this by updating the app.localsvariable for that app in app.js
通过更新该app.locals应用程序的变量来做到这一点的一种方法app.js
Set via following
通过以下方式设置
var app = express();
app.locals.appName = "DRC on FHIR";
Get / Access
获取/访问
app.listen(3000, function () {
console.log('[' + app.locals.appName + '] => app listening on port 3001!');
});
Elaborating with a screenshot from @RamRovi example with slight enhancement.
详细说明来自@RamRovi 示例的屏幕截图,并略有增强。
回答by Shaik Matheen
you can also use "global"
您也可以使用“全局”
Example:
例子:
declare like this :
像这样声明:
app.use(function(req,res,next){
global.site_url = req.headers.host; // hostname = 'localhost:8080'
next();
});
Use like this: in any views or ejs file <% console.log(site_url); %>
像这样使用:在任何视图或 ejs 文件中 <% console.log(site_url); %>
in js files console.log(site_url);
在 js 文件中 console.log(site_url);
回答by dewwwald
What I do in order to avoid having a polluted global scope is to create a script that I can include anywhere.
为了避免污染全局范围,我所做的是创建一个可以包含在任何地方的脚本。
// 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;
Doing this will only create a new instance once and share that everywhere where the file is included. I am not sure if it is because the variable is cached or of it because of an internal reference mechanism for the application (that might include caching). Any comments on how node resolves this would be great.
这样做只会创建一个新实例并在包含文件的任何地方共享该实例。我不确定是因为变量被缓存还是因为应用程序的内部引用机制(可能包括缓存)。关于节点如何解决这个问题的任何评论都会很棒。
Maybe also read this to get the gist on how require works: http://fredkschott.com/post/2014/06/require-and-the-module-system/
也许还可以阅读本文以了解 require 如何工作的要点:http: //fredkschott.com/post/2014/06/require-and-the-module-system/


