【问题标题】:How to pass variable from jade template file to a script file?如何将变量从玉模板文件传递到脚本文件?
【发布时间】:2012-01-31 16:22:11
【问题描述】:

我在使用未传递给 javascript 文件的玉模板文件 (index.jade) 中声明的变量 (config) 时遇到问题,这会导致我的 javascript 崩溃。这是文件(views/index.jade):

h1 #{title}

script(src='./socket.io/socket.io.js')
script(type='text/javascript')
  var config = {};
  config.address = '#{address}';
  config.port = '#{port}';
script(src='./javascripts/app.js')

这是我的 app.js 的一部分(服务器端):

  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.set('address', 'localhost');
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

app.get('/', function(req, res){
  res.render('index', {
    address: app.settings.address,
    port: app.settings.port
});
});

if (!module.parent) {
  app.listen(app.settings.port);
  console.log("Server listening on port %d",
app.settings.port);
}

// Start my Socket.io app and pass in the socket
require('./socketapp').start(io.listen(app));

这是我崩溃的 javascript 文件的一部分 (public/javascripts/app.js):

(function() {
        var socket = new io.Socket(config.address, {port: config.port, rememberTransport: false});

我在本地主机(我自己的机器)上以开发模式 (NODE_ENV=development) 运行该站点。我正在使用 node-inspector 进行调试,它告诉我配置变量在 public/javascripts/app.js 中未定义。

有什么想法吗??谢谢!!

【问题讨论】:

标签: javascript node.js pug


【解决方案1】:

#{} 用于转义的string interpolation,它会自动转义输入,因此更适合纯字符串而不是JS对象:

script var data = #{JSON.stringify(data)}
<script>var data = {&quot;foo&quot;:&quot;bar&quot;} </script>

!{}用于unescaped code插值,更适合对象

script var data = !{JSON.stringify(data)}
<script>var data = {"foo":"bar"} </script>

注意未转义的代码可能很危险。您必须确保清理所有用户输入以避免跨站点脚本 (XSS)。

例如:

{ foo: 'bar </script><script> alert("xss") //' }

会变成:

<script>var data = {"foo":"bar </script><script> alert("xss") //"}</script>

可能的解决方案:使用.replace(/&lt;\//g, '&lt;\\/')

script var data = !{JSON.stringify(data).replace(/<\//g, '<\\/')}
<script>var data = {"foo":"bar<\/script><script>alert(\"xss\")//"}</script>

这个想法是为了防止攻击者:

  1. 脱离变量:JSON.stringify 转义引号
  2. 脱离脚本标签:如果变量内容(例如,如果来自数据库,您可能无法控制)具有&lt;/script&gt; 字符串,则替换语句将处理它

https://github.com/pugjs/pug/blob/355d3dae/examples/dynamicscript.pug

【讨论】:

  • 很好的答案,它适用于对象!顺便说一句,JSON 是一个全局对象吗?它似乎无需导入任何其他库即可工作。如果是这样,浏览器支持呢?
  • @chharvey JSON 是一种内置的javascript语言(如日期或数学),所有浏览器都支持它。
  • @laggingreflex 谢谢。我知道 JSON 本身是什么,但我不确定实际的 JSON 对象是什么。
  • 如果 JSON 对象很大。 JSON.stringify(data) 阻塞事件循环并同步字符串化数据。有什么办法可以解决这个问题?
  • 同意这是最好的答案,但我认为这不是逃避潜在危险字符串的正确位置。 IMO 最好在此代码中省略 replace 调用,并将此值视为任何其他输入。 JSON.stringify 保证生成有效的 javascript(或失败),并且在内存中有这个潜在的危险值之后,您可以确保在使用前根据需要对其进行清理。
【解决方案2】:

如果您像我一样,并且经常使用这种传递变量的方法,那么这里有一个无需编写代码的解决方案。

在您的 node.js 路由中,将变量传递到名为 window 的对象中,如下所示:

router.get('/', function (req, res, next) {
    res.render('index', {
        window: {
            instance: instance
        }
    });
});

然后在您的 pug/jade 布局文件中(就在 block content 之前),您可以像这样将它们取出:

if window
    each object, key in window
        script.
            window.!{key} = !{JSON.stringify(object)};

当我的 layout.pug 文件与每个 pug 文件一起加载时,我不需要一遍又一遍地“导入”我的变量。

这样,所有传递给 window 的变量/对象“神奇地”最终都在浏览器的真实 window 对象中,您可以在 Reactjs、Angular 或 vanilla javascript 中使用它们。

【讨论】:

    【解决方案3】:

    就我而言,我试图通过快速路由(类似于 OP 设置)将对象传递到模板中。然后我想将该对象传递给我通过 pug 模板中的脚本标记调用的函数。虽然lagginreflex's answer 让我很接近,但我最终得到了以下结果:

    script.
        var data = JSON.parse('!{JSON.stringify(routeObj)}');
        funcName(data)
    

    这确保了对象按预期传递,而不需要在函数中反序列化。此外,其他答案似乎适用于原语,但是当数组等与对象一起传递时,它们被解析为字符串值。

    【讨论】:

      【解决方案4】:

      这是我解决这个问题的方法(使用 MEAN 导数)

      我的变量:

      {
        NODE_ENV : development,
        ...
        ui_varables {
           var1: one,
           var2: two
        }
      }
      

      首先,我必须确保传递了必要的配置变量。 MEAN 使用 node nconf 包,默认设置为限制从环境传递的变量。我必须解决这个问题:

      config/config.js:

      原文:

      nconf.argv()
        .env(['PORT', 'NODE_ENV', 'FORCE_DB_SYNC'] ) // Load only these environment variables
        .defaults({
        store: {
          NODE_ENV: 'development'
        }
      });
      

      修改后:

      nconf.argv()
        .env('__') // Load ALL environment variables
        // double-underscore replaces : as a way to denote hierarchy
        .defaults({
        store: {
          NODE_ENV: 'development'
        }
      });
      

      现在我可以像这样设置我的变量了:

      export ui_varables__var1=first-value
      export ui_varables__var2=second-value
      

      注意:我将“层次结构指示器”重置为“__”(双下划线),因为它的默认值是“:”,这使得从 bash 中设置变量更加困难。请参阅此线程上的另一篇文章。

      现在是翡翠部分: 接下来需要呈现这些值,以便 javascript 可以在客户端获取它们。将这些值写入索引文件的直接方法。因为这是一个单页应用程序(角度),所以这个页面总是首先加载。我认为理想情况下这应该是一个 javascript 包含文件(只是为了保持干净),但这对于演示很有用。

      app/controllers/index.js:

      'use strict';
      var config = require('../../config/config');
      
      exports.render = function(req, res) {
        res.render('index', {
          user: req.user ? JSON.stringify(req.user) : "null",
          //new lines follow:
          config_defaults : {
             ui_defaults: JSON.stringify(config.configwriter_ui).replace(/<\//g, '<\\/')  //NOTE: the replace is xss prevention
          }
        });
      };
      

      app/views/index.jade:

      extends layouts/default
      
      block content
        section(ui-view)
          script(type="text/javascript").
          window.user = !{user};
          //new line here
          defaults = !{config_defaults.ui_defaults};
      

      在我渲染的 html 中,这给了我一个不错的小脚本:

      <script type="text/javascript">
       window.user = null;         
       defaults = {"var1":"first-value","var2:"second-value"};
      </script>        
      

      从这一点来看,angular 使用代码很容易。

      【讨论】:

      • 这是一种非常冗长的方式来说明已接受的答案已经说了些什么。此外,提及 MEAN、nconf 等是无关紧要的。问题是关于如何将变量传递给客户端,而不是关于你如何做你的开发堆栈。不过不要投反对票,因为您仍然在这个答案中付出了很多努力。
      【解决方案5】:

      有点晚了,但是...

      script.
        loginName="#{login}";
      

      这在我的脚本中运行良好。在 Express 中,我正在这样做:

      exports.index = function(req, res){
        res.render( 'index',  { layout:false, login: req.session.login } );
      };
      

      我猜最新的玉不一样?

      佣兵。

      编辑:添加“。”在脚本之后防止 Jade 警告。

      【讨论】:

      • 是的,我也通过将模板中的局部变量用引号和 #{} 指示符包裹起来来实现这一点。
      • 这个答案很危险,lagginreflex 的答案正确编码了字符串(登录名中的换行符可能允许代码执行)。
      • 所以问题只是单引号,而双引号是预期的,对吧?
      • 对我来说问题是点。我在脚本块的末尾有它。在“脚本”关键字后面加上点,它就像一个魅力。谢谢!
      【解决方案6】:

      看到这个问题:JADE + EXPRESS: Iterating over object in inline JS code (client-side)?

      我也有同样的问题。 Jade 不会将局部变量(或根本不做任何模板)传递给 javascript 脚本,它只是将整个块作为文本传递。如果您在脚本标签上方的 Jade 文件中使用局部变量“地址”和“端口”,它们应该会显示出来。

      我在上面链接的问题中列出了可能的解决方案,但您可以: - 将每一行作为非转义文本传递(!= 在每一行的开头),并简单地将“-”放在使用局部变量的每一行 javascript 之前,或者: - 通过 dom 元素传递变量并通过 JQuery 访问(丑陋)

      没有更好的方法吗? Jade 的创建者似乎不想要多行 javascript 支持,如 GitHub 中的此线程所示:https://github.com/visionmedia/jade/pull/405

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-09
        • 2018-03-02
        • 2011-10-23
        • 2015-08-24
        • 1970-01-01
        • 2021-09-22
        相关资源
        最近更新 更多