【问题标题】:Express.js View "globals"Express.js 查看“全局”
【发布时间】:2011-06-10 18:26:20
【问题描述】:

我正在使用 Express.js(在 Node.js 上),我知道您可以通过“locals”参数呈现带有自定义数据的视图。 (res.render("template", { locals: { foo: "bar" } });)

有没有办法拥有“全局”? (即每个视图都可以访问的数据)

我看到了view options,但这不是递归的,所以如果我在模板中使用任何本地人,它会替换我设置的本地人。

这是我的用例:我想让它可以在每页的基础上添加 CSS/JS 文件,这是我主要布局的一部分。问题是,如果我没有在每个渲染上明确设置这些数组,我会得到一个未定义的错误,所以在我的模板中我总是必须做typeof css !== "undefined" 舞蹈。此外,我还有其他选择框选项列表,我不想显式添加到我的每个表单中。

【问题讨论】:

  • 您不能通过定义一个具有全局范围的变量(例如通过您的 require 语句)然后在您的一个 app.get 调用中引用它来做到这一点吗?
  • 是的,但是我仍然必须在每次调用 render() 时明确地传递该数据。
  • 哈哈!我发现自己正在寻找这个解决方案,而我又回到了一月份的时候。感谢您提出这个问题!

标签: javascript node.js express


【解决方案1】:

完成此操作的最简单方法是创建一个变量,该变量代表视图的默认局部变量集。然后创建一个接受对象的函数,将其与局部变量合并,并返回合并后的对象。

我还在容器对象中传递我的所有本地人,即{locals:{g:{prop:val}}},所以在我看来,我可以引用g.prop,它在未设置时只会返回null,而不是抛出一个未定义的错误。

function default_page_vars(custom_vars){
    var vars = {
        footer: true,
        host: req.headers.host.split(':')[0],
        config: this.config
    };

    if(custom_vars){
        for(var k in custom_vars){
            vars[k] = custom_vars[k];
        }
    }
    return {
        g:vars
    };
}

//within your handler
response.render(view, {
    locals: default_page_vars(other_locals)
});

【讨论】:

    【解决方案2】:

    我最终研究了源代码,实际上我发现现在这在 Express 的从未有过的版本中是可能的。 (到目前为止,只能通过 GitHub 获得)

    【讨论】:

    • 您介意分享您找到的来源的链接吗?我正在尝试做同样的事情。谢谢。
    • 现在的版本(v2+)允许app.set("view options", { ...default values... });
    • @domonic 那些默认值是什么?或者至少在哪里列出?
    【解决方案3】:

    有一种方法可以为视图设置“全局”变量,使用动态视图助手。

    来自 Express.js 指南:

    app.dynamicHelpers(obj)

    注册动态视图助手。 动态视图助手很简单 接受 req、res 和 针对服务器进行评估 渲染视图之前的实例。 这个函数的返回值 成为局部变量 相关联。

    app.dynamicHelpers({ 会话: 函数(请求,资源){ 返回req.session; } });

    现在所有视图都有会话 可用,以便会话数据可以 通过 session.name 等访问:

    您可以在此处找到有关如何使用它们的真实示例:https://github.com/alessioalex/Nodetuts/tree/master/express_samples(节点 app.js 以启动应用程序)

    【讨论】:

      【解决方案4】:

      作者提到的使用视图选项的真实示例:

      var app = express.createServer();
      
      app.configure(function() {
        app.set('views', path.join(__dirname, '..', 'views'));
        app.set('view engine', 'jade');
        app.set('view options', {
          assetVersion: 1
        });
      

      然后在我的 layout.jade 中(在我的例子中是应用程序的基本模板):

      link(rel='stylesheet', href='/static/css/' + assetVersion + '/style.css')
      script(src='/static/js/' + assetVersion + '/script.js')
      

      有了这个小技巧,我只需将assetVersion 变量更新到一个地方,以确保我的资产没有缓存在 Varnish 或其他地方。

      【讨论】:

        【解决方案5】:

        对于自 Express 3 发布以来可能遇到此问题的人来说,值得注意的是,“dynamicHelpers”方法不再存在。

        相反,您可以使用 app.locals 函数,它作为一个对象,您可以在其中存储值或函数,然后将它们提供给视图。例如:-

        // In your app.js etc.
        app.locals.title = "My App";
        app.locals({
            version: 3,
            somefunction: function() {
                return "function result";
            }
        });
        
        // Then in your templates (shown here using a jade template)
        
        =title
        =version
        =somefunction()  
        
        // Will output
        
        My App
        3
        function result
        

        如果您需要访问请求对象以从中提取信息,您可以编写一个简单的中间件函数并使用 app.settings 变量。

        例如,如果您使用 connect-flash 向您的用户提供消息,您可能会执行以下操作:

        app.use(function(req, res, next) {
            app.set('error', req.flash('error'));
            next();
        });
        

        这将使您可以访问模板中带有 =settings.error 的错误消息。

        这里涵盖了这些主题,虽然有点简短:http://expressjs.com/api.html#app.locals

        更新:Express 4

        app.locals 现在是一个简单的 JavaScript 对象,所以每个属性都必须一个一个地设置。

        app.locals.version = 3;
        app.locals.somefunction = function() {
            return "function result";
        }
        

        res.locals 提供完全相同的功能,除了它应该用于请求特定的数据而不是应用程序范围的数据。用户对象或设置是常见的用例。

        res.locals.user = req.isAuthenticated() ? req.user : null;
        res.locals.userSettings = {
            backgroundColor: 'fff'
        }
        

        【讨论】:

        • 我找到的最好的解释。我已经冲刷过了。谢谢。
        • app.set('error', msg) 会为整个应用程序设置错误,而不仅仅是发出请求的用户,还是我错了?
        • 你的解释太棒了。但是当我尝试使用“=title”在我的 Jade 文件中显示全局变量时,什么也没有出现。为此,我应该使用以下合成器“#{title}”来正确显示我的变量。
        • 感谢@Pier-LucGendreau!
        【解决方案6】:

        这是一个隐藏的响应,但我终于让它起作用了。

        1) 这是一个围绕模块 connect-flash

        的示例

        2)在server.js/app.js中添加一个中间件,将req添加到locals。这允许模板在需要时调用request.flash()。没有这个,flash() 会在每个请求/重定向失败时消耗。

        var app = module.exports = express()
          , flash=require('connect-flash');
        app.configure(function(){
          ...
          app.use(express.session({ secret: "shhh" }));
        
          // Start Router
          app.use(flash());
          app.use(function(req, res, next) {
            res.locals.request = req;
            next();
          });
        
          app.use(app.router);
        });
        

        3) 像往常一样设置你的路线(这是coffeescript,但没什么特别的)

        app.get '/home', (req, res) ->
          req.flash "info", "this"
          res.render "#{__dirname}/views/index"
        

        4) 当你想要消息时调用 request.flash()。每次通话都会消耗它们,所以不要控制台记录它们,否则它们会消失 :-)

        !!!
        html
          head
            title= config.appTitle
            include partials/_styles
        
          body
            include partials/_scripts
        
            #header
              a(href="/logout") Logout CURRENTUSER
              h2= config.appTitle
        
            #messages
              - var flash = request.flash()
              each flashType in ['info','warn','error']
                if flash[flashType]
                  p.flash(class=flashType)
                    = flash[flashType]
        
        
            block content
              h1 content here
        

        【讨论】:

        • 我建议不要传递整个请求对象。 //总是包含 flash app.use(function(req, res, next) { res.locals.flasher = {} ; res.locals.flasher.flash = req.flash; res.locals.flasher.session = req.session ; 下一个(); });
        【解决方案7】:

        快递4

        您可以访问应用程序中呈现的模板中的局部变量。

        因此,如果您想在模板中使用任何本地变量 => 假设您已将模板引擎 npm 安装到您的 node/express 应用程序中。

        首先,您需要在app.js 文件中使用您的自定义变量设置express locals objects,如果需要多个值,您可以使用一个对象(我们在这篇文章中的例子)

         /**
          *  Set locals object
          */
        
         app.locals.layoutData = { 
          site: {
              title: 'MyWebSiteTitle',
          },   
          metaTag: {
              charset: 'UTF-8',
              description: 'MyDescription',
              keywords: 'keyword-1,keyword-2,...',
              author: 'MyName',
              viewport: 'width=device-width, initial-scale=1.0'
          }
         };
        

        然后,访问模板文件layout.pug中的值(以PUG模板引擎为例)

        doctype html
        html
          head
            //title
            title #{locals.layoutData.site.title}
            //Describe metadata
            meta(charset=layoutData.metaTag.charset)
            meta(name='description', content=locals.layoutData.metaTag.description)
            meta(name='keywords', content=locals.layoutData.metaTag.keywords)
            meta(name='author', content=locals.layoutData.metaTag.author)
            meta(name='viewport', content=locals.layoutData.metaTag.viewport)
          body
              block content
              br
              hr
              footer
                p All rights reserved © 2018 |  #{locals.layoutData.site.title}
        

        经过测试

          "dependencies": {
            "express": "^4.16.3",
            "pug": "^2.0.3"
          }
        

        【讨论】:

          猜你喜欢
          • 2013-05-23
          • 1970-01-01
          • 2021-02-24
          • 2019-05-09
          • 1970-01-01
          • 1970-01-01
          • 2012-06-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多