如何将变量从玉模板文件传递到脚本文件?

IT技术 javascript node.js pug
2021-01-28 17:58:44

我在 jade 模板文件 (index.jade) 中声明的变量 (config) 遇到了问题,该文件未传递给 javascript 文件,然后使我的 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 中未定义配置变量。

有任何想法吗??谢谢!!

6个回答

这是一个有点晚了,但...

script.
  loginName="#{login}";

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

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

我猜最新的玉是不同的?

梅尔。

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

是的,我也通过将模板中的局部变量用引号和 #{} 指示符包装来实现此目的。
2021-03-17 17:58:44
对我来说,问题是点。我在脚本块的末尾有它。在“script”关键字后面加上点,它的作用就像一个魅力。谢谢!
2021-03-19 17:58:44
所以问题只是单引号,而双引号是预期的,对吗?
2021-03-24 17:58:44
这个答案很危险, lagginreflex 的答案正确地编码了字符串(登录名中的换行符可能允许代码执行)。
2021-04-09 17:58:44

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

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

!{}用于非转义代码插值,更适合对象

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(/<\//g, '<\\/')

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

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

  1. 跳出变量:JSON.stringify转义引号
  2. 打破脚本标签:如果变量内容(例如,如果来自数据库,你可能无法控制)有一个</script>字符串,替换语句会处理它

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

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

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

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

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

如果你像我一样经常使用这种传递变量的方法,这里有一个少写代码的解决方案。

在您的 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 中使用它们。

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

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

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

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