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

2023-12-14

好的,所以我用它建立了一个博客Jekyll你可以在文件中定义变量_config.yml可在所有模板/布局中访问。我目前正在使用Node.JS / Express with EJS模板和ejs-本地人(对于部分/布局。我希望做一些类似于全局变量的事情,例如site.title发现于_config.yml如果有人熟悉杰基尔。我有诸如网站标题(而不是页面标题)、作者/公司名称之类的变量,这些变量在我的所有页面上都保持不变。

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

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。有没有办法做到这一点,同时仍然允许我传递特定于每个页面的其他变量?


Express 版本 4/5+ 的更新:

处理这个问题的最佳解决方案仍然是使用应用程序.locals如 Express API 参考中所述。正如此处的一些评论所指出的,API 在 Express 4 中进行了更新,以便app.locals不再是一个函数,而只是一个对象。因此,如果您尝试将其作为函数调用,您将收到错误。

要在 Express 4/5+ 中使用 app.locals 来完成与下面 Express 3 的原始示例相同的操作,您可以设置app.locals就像应用程序中可以访问 Express 的任何地方一样app object:

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]'
    }
};

这将使所有这些值在所有可访问的视图中全局可用site.title, site.description, author.name, and author.contact分别。

NOTE:或者,您也可以设置值app.locals分别地。

例如,这也可以工作:

app.locals.authorName = 'Cory Gross';
app.locals.authorContact = '[email protected]';

但是,默认情况下,这将not工作,并且会抛出错误:

app.locals.author.name = 'Cory Gross';
app.locals.author.contact = '[email protected]';

发生这种情况是因为,虽然app.locals已经作为 Express 公开的对象存在,您可以在其上定义属性,app.locals.author尚不存在,因此上面的代码会抛出一个错误,抱怨您试图在未定义的对象上设置属性。为了执行上述操作,您首先必须设置app.locals.author = {}作为一个空对象或只是将所有内容设置为app.locals or app.locals.author同时,类似于我上面的第一个例子。

中间件中的用法

虽然,设置的值app.locals在所有视图中都可以全局访问,但在 Express 3 中使用它的潜在问题之一是默认情况下这些值不一定可以在中间件函数中访问。由于这一限制,一种替代方案,如最初建议的那样皮克尔的回答,正在将值设置为res.locals相反,在顶级中间件中,以便这些值在所有较低的中间件以及所有视图中都可用。然而,这种替代方案有一个缺点,即设置所有这些值的逻辑将针对每个请求/响应一遍又一遍地执行,而不是像以下情况那样只设置一次并在服务器运行期间持续存在app.locals.

在 Express 4/5+ 中,如果您想要设置的值,现在有更好的解决方案app.locals可在中间件功能以及所有视图中使用。为了解决这个问题,Express 4/5+ API 现在公开了 Expressapp所有中间件函数中的对象,可作为属性访问req参数为req.app。因此,默认情况下,您现在可以轻松访问设置的所有全局应用程序范围值app.locals在所有中间件功能中以及简单地通过访问对象req.app.locals在你的中间件中。

Express 版本 3 的原始答案:

在有机会学习之后Express 3 API 参考再多一点我就发现了我在寻找的东西。具体来说,条目为应用程序.locals然后再往下一点当地人资源那里有我需要的答案。

我自己发现这个功能app.locals获取一个对象并将其所有属性存储为应用程序范围内的全局变量。这些全局变量作为局部变量传递给每个视图。功能res.locals但是,其范围仅限于请求,因此响应局部变量只能由在该特定请求/响应期间呈现的视图访问。

所以对于我的情况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]'
    }
});

然后所有这些变量都可以在我的视图中访问site.title, site.description, author.name, author.contact.

我还可以为请求的每个响应定义局部变量res.locals,或者简单地传递诸如页面标题之类的变量作为options中的参数render call.

EDIT:这个方法将not允许您在中间件中使用这些本地变量。事实上,正如皮克斯在下面的评论中所建议的那样,我确实遇到了这个问题。在这种情况下,您将需要在他的替代(和赞赏的)答案中创建一个中间件功能。您的中间件功能需要将它们添加到res.locals对于每个响应,然后调用next。该中间件函数需要放置在需要使用这些局部变量的任何其他中间件之上。

EDIT:通过声明当地人之间的另一个区别app.locals and res.locals是与app.locals变量仅设置一次并在应用程序的整个生命周期中持续存在。当您设置当地人时res.locals在您的中间件中,每次收到请求时都会设置这些。你基本上应该更喜欢通过设置全局变量app.locals除非该值取决于请求req变量传递到中间件。如果该值没有改变,那么只设置一次会更有效app.locals.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Express / Node.JS 创建可在所有视图中访问的全局变量? 的相关文章

随机推荐