好了,我已经使用Jekyll构建了一个博客,你可以在一个文件_config.yml
中定义变量,这些变量可以在所有的模板/布局中访问。我目前使用Node.JS/Express与EJS模板和ejs-locals(用于部分/布局)。如果有人熟悉Jekyll,我希望做一些类似于_config.yml
中的site.title
全局变量的事情。我有像网站标题(而不是页面标题),作者/公司名称这样的变量,这些变量在我所有的页面上都是一样的。
以下是我目前正在做的一个例子:
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
});
};
字符串
我希望能够定义像我的网站的标题,描述,作者等变量在一个地方,并有他们在我的布局/模板通过EJS访问,而不必通过它们作为选项,每个调用res.render
。有没有一种方法可以做到这一点,并仍然允许我在其他变量特定于每个页面?
8条答案
按热度按时间ufj5ltwl1#
Express 4/5+版本更新:
处理这个问题的最佳解决方案仍然是使用app.locals,如API参考中所述。正如这里的一些评论所指出的,API在Express 4中进行了更新,使得
app.locals
不再是一个函数,而现在只是一个对象。所以如果你试图把它作为一个函数调用,你会得到一个错误。要在Express 4/5+中使用app.locals来完成与我下面的Express 3原始示例相同的事情,您可以在应用程序中可以访问Express
app
对象的任何地方设置app.locals
:字符串
这将使所有这些值在所有视图中全局可用,可分别作为
site.title
、site.description
、author.name
和author.contact
访问。**注:**或者,您也可以单独设置
app.locals
上的值。例如,这也可以工作:
型
但是,在默认情况下,这将 * 不**工作,并会抛出错误:
型
这是因为,虽然
app.locals
已经作为Express公开的对象存在,您可以在其上定义属性,但app.locals.author
还不存在,因此上面的代码将抛出一个错误,抱怨您试图在未定义的对象上设置属性。为了做到这一点,你首先必须将app.locals.author = {}
设置为空对象,或者同时设置app.locals
或app.locals.author
下的所有内容,类似于我上面的第一个例子。中间件使用
尽管
app.locals
上设置的值在所有视图中都可以全局访问,但在Express 3中使用它的潜在问题之一是,默认情况下,这些值不一定可以在中间件函数中访问。由于这个限制,一个替代方案,如最初在Pickel's answer中建议的那样,是在顶级中间件中设置res.locals
上的值,以便这些值在所有较低的中间件以及所有视图中都可用。然而,这种替代方案的缺点是,设置所有这些值的逻辑将为每个请求/响应反复执行,而不是像app.locals
那样设置一次并持续到服务器运行。在Express 4/5+中,如果您希望在
app.locals
上设置的值在中间件函数和所有视图中可用,现在有一个更好的解决方案。为了解决这个问题,Express 4/5+ API现在在所有中间件函数中公开Expressapp
对象,可以作为req
参数的属性req.app
访问。因此,默认情况下,您现在可以轻松地访问所有中间件函数中在app.locals
上设置的所有全局应用程序范围的值,只需在中间件中以req.app.locals
的身份访问该对象即可。Express第三版原始答案:
在有机会对Express 3 API Reference进行了更多的研究之后,我发现了我要找的东西。具体来说,app.locals的条目和更下面的res.locals包含了我需要的答案。
我自己发现,函数
app.locals
接受一个对象,并将其所有属性存储为应用程序范围内的全局变量。这些全局变量作为局部变量传递给每个视图。然而,函数res.locals
的作用域是请求,因此,响应局部变量只能由在特定请求/响应期间呈现的视图访问。因此,对于我的
app.js
案例,我所做的是添加:型
然后所有这些变量在我的视图中都可以访问为
site.title
,site.description
,author.name
,author.contact
。我还可以用
res.locals
为请求的每个响应定义局部变量,或者简单地将页面标题之类的变量作为render
调用中的options
参数传递。**EDIT:**此方法将 * 不 * 允许您在中间件中使用这些局部变量。实际上,正如皮克尔斯在下面的评论中所建议的那样,我确实遇到了这个问题。在这种情况下,您将需要创建一个中间件功能,就像他的替代(和赞赏)答案一样。您的中间件函数需要为每个响应将它们添加到
res.locals
,然后调用next
。这个中间件函数需要放在需要使用这些局部变量的任何其他中间件之上。**编辑:**通过
app.locals
和res.locals
声明局部变量的另一个区别是,使用app.locals
时,变量只设置一次,并在应用程序的整个生命周期中持续存在。当您在中间件中使用res.locals
设置局部变量时,每次收到请求时都会设置这些变量。基本上,您应该更喜欢通过app.locals
设置全局变量,除非该值取决于传入中间件的请求req
变量。如果该值没有改变,那么在app.locals
中只设置一次会更有效。o0lyfsai2#
您可以通过将它们添加到通用中间件中的locals对象来实现这一点。
字符串
Locals也是一个扩展局部变量对象而不是覆盖它的函数。所以下面的也可以
型
完整示例
型
我还添加了一个通用的渲染中间件。这样你就不需要为每个路由添加res.render,这意味着你有更好的代码重用。一旦你沿着可重用中间件的路线走下去,你会注意到你将拥有大量的构建块,这将极大地加快开发速度。
z9ju0rcb3#
对于Express4.0,我发现使用应用程序级变量的工作方式略有不同& Cory的答案对我不起作用。
从文档:http://expressjs.com/en/api.html#app.locals
我发现可以在
字符串
例如
型
然后在应用程序中可以访问这些变量&在Express中间件中可以在Req对象中作为
型
例如,在
型
ki1q1bka4#
在app.js中,你需要添加如下内容
字符串
现在,在您想要使用此变量的所有文件中,您可以仅以
myvar
的形式访问它ppcbkaq55#
一种方法是在
app.js
中更新该应用程序的app.locals
变量通过以下设置
字符串
获取/访问
型
详细说明来自@RamRovi示例的屏幕截图,略有增强。
x1c 0d1x的数据
0dxa2lsx6#
你也可以使用“全局”
示例如下:
这样宣布:
字符串
像这样使用:在任何视图或ejs文件<% console.log(site_url); %>
在js文件中console.log(site_url);
gorkyyrv7#
有了不同的答案,我实现了这段代码来使用加载在“app.locals”中的外部文件JSON
参数
字符串
申请
型
EJS页面
型
希望能有所帮助
lg40wkob8#
为了避免全局作用域被污染,我所做的是创建一个可以包含在任何地方的脚本。
字符串
这样做只会创建一个新示例一次,并在包含该文件的任何地方共享该示例。我不确定这是因为变量被缓存了,还是因为应用程序的内部引用机制(可能包括缓存)。任何关于节点如何解决这个问题的评论都是很好的。
也许还可以阅读以下内容来了解require是如何工作的:http://fredkschott.com/post/2014/06/require-and-the-module-system/