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

时间:2013-05-08 23:52:05

标签: node.js express sails.js template-engine ejs

好的,所以我使用Jekyll构建了一个博客,您可以在文件_config.yml中定义可在所有模板/布局中访问的变量。我目前正在使用Node.JS / ExpressEJS模板和ejs-locals(对于部分/布局。我希望做类似于{{1}等全局变量的操作如果有人熟悉Jekyll,可以在site.title中找到。我有变量,如网站的标题,(而不是页面标题),作者/公司名称,在我的所有页面上保持不变。

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

_config.yml

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

8 个答案:

答案 0 :(得分:99)

在有机会研究Express 3 API Reference之后,我发现了我在寻找的东西。具体来说,app.locals的条目然后再向下res.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: 'CoryG89@gmail.com'
    }
});

然后,在我的观看中,所有这些变量都可以site.titlesite.descriptionauthor.nameauthor.contact访问。

我还可以为res.locals的请求的每个响应定义局部变量,或者只是将页面标题等变量作为options调用中的render参数传递。

编辑:此方法允许您在中间件中使用这些本地人。我确实碰到了这一点,正如Pickels在下面的评论中所暗示的那样。在这种情况下,您需要在他的替代(和赞赏)答案中创建一个中间件功能。您的中间件功能需要将每个响应添加到res.locals,然后调用next。这个中间件功能需要放在需要使用这些本地的任何其他中间件之上。

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

答案 1 :(得分:48)

您可以通过将它们添加到普通中间件中的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也是一个扩展locals对象而不是覆盖它的函数。所以以下工作也是如此

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,这意味着您可以更好地重用代码。一旦你沿着可重复使用的中间件路线走下去,你就会发现你将拥有许多构件,这将大大加快开发速度。

答案 2 :(得分:16)

对于Express 4.0,我发现使用应用程序级变量的工作方式略有不同。科里的回答对我不起作用。

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

我发现您可以在

中为应用声明一个全局变量
app.locals

e.g

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

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

req.app.locals.baseUrl

e.g。

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

答案 3 :(得分:12)

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

global.myvar = 100;

现在,在您要使用此变量的所有文件中,您只需将其作为myvar

进行访问即可

答案 4 :(得分:1)

通过在app.locals

中更新该应用的app.js变量来实现此目的的一种方法

通过以下

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

获取/访问

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

使用@RamRovi示例中的屏幕截图进行详细说明,并略微增强。

enter image description here

答案 5 :(得分:1)

你也可以使用“全球”

示例:

声明如下:

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

像这样使用:   在任何视图或ejs文件中      <%          的console.log(SITE_URL);       %GT;

在js文件中      的console.log(SITE_URL);

答案 6 :(得分:0)

我为避免污染全局范围而做的是创建一个可以包含在任何地方的脚本。

// 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;

这样做只会创建一个新实例,并在包含文件的任何地方共享。我不确定是因为变量是缓存的还是由于应用程序的内部引用机制(可能包括缓存)。关于节点如何解决这个问题的任何评论都会很棒。

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

答案 7 :(得分:0)

使用不同的答案,我实现了此代码,以使用在“ app.locals”中加载的外部文件JSON

参数

{
    "web": {
        "title" : "Le titre de ma Page",
        "cssFile" : "20200608_1018.css"
    }
}

应用

var express     = require('express');
var appli       = express();
var serveur     = require('http').Server(appli);

var myParams    = require('./include/my_params.json');
var myFonctions = require('./include/my_fonctions.js');

appli.locals = myParams;

EJS页面

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title><%= web.title %></title>
    <link rel="stylesheet" type="text/css" href="/css/<%= web.cssFile %>">
</head>

</body>
</html>

希望它会有所帮助