转义包含撇号的Mustache变量以用于JavaScript。

10

我有一个变量({{title}}),其中包含一个撇号。Mustache会将其转义为'

但是,以下模板导致JavaScript错误(Expected token ')'):

<a href="javascript:confirm('{{title}}?');">{{title}}</a>

Mustache渲染后,语法错误变得清晰明了('Joe's Lame?'):


<a href="javascript:confirm('Joe's Lame?');">Joe's Lame</a>

我仍在学习Mustache,尽管这个例子是刻意编造的,但在这种情况下正确的转义变量的方法是什么。

参考示例


有趣!我想这在 Mustache 中不可能。但在 Handlebars (Handlebars.registerHelper) 中应该不是什么大问题... - hgoebl
@hgoebl,解决方案不一定非得是Mustache。 - Jason McCreary
那么你应该看一下Handlebars。它是Mustache的超集,可以非常容易地进行扩展。你需要创建并注册一个helper函数,比如escapeJs,然后在你的模板中像这样使用它:{{escapeJS title}}。如果我有时间,我会fork你的fiddle... - hgoebl
我知道这只是一个愚蠢的解决方法(用另一个字符替换撇号问题),但一个快速而不太优美的解决方案是:"<a href='javascript:confirm(\"{{title}}\");'>{{title</a>}}" - hgoebl
@hgoebl,我同意那会起作用。我是在问JavaScript或Mustache是否有我所忽略的东西。 - Jason McCreary
2个回答

6

注:我知道这是一篇旧文章,但如果有人发现它有用的话,请留下。像我一样,在了解三重括号解决方案之前,我也先发现了你的帖子。

在Mustache中,只需使用三重括号,不必感到头痛:

{{{title}}}

但是对于您的情况,仅仅通过转义单引号是不够的。你还需要将单引号和双引号进行反转,像这样:

<a href='javascript:confirm("{{{title}}}?");'>{{{title}}}</a>

“你还应该反转单引号和双引号” - 这并不重要。转义需要能够处理两者。 - Bergi
@Bergi:提问者只要求转义{{title}}变量,而不是整个锚点标签。上面的答案提供了转义整个锚点标签的解决方案,但也没有被标记为答案。 - Antonio Ooi
@Bergi:我的回答直接涉及Mustache的解决方案,并且它与JS字符串所需的本地解决方案一起工作。我不想在这里创建不必要的对话,可能会违反Stack Overflow的规则,但是除了{{title}}之外,整个JS字符串都没有要求转义。 - Antonio Ooi
我真的不确定 - 我们只关心属性值,而不是整个标签?而且,如果 title 包含双引号,你的解决方案是无效的。如果你说这就是 OP 要求的并想提供一个有问题的解决方案,请至少添加一个有关 XSS 的警告。 - Bergi
@Bergi:显然,OP标题中说的是撇号。为什么不让OP把整个项目代码发送给你,也为他解决呢?我只是根据SCOPE回答,我的回答没有问题。如果你想让这变成一次长谈,我可以陪你。 - Antonio Ooi
显示剩余2条评论

3
如果不一定要使用Mustache,那么您可以使用一种称为Handlebars的Mustache超集。
首先注册一个Handlebars帮助程序:
Handlebars.registerHelper('escapeJs', function(str) {
    return str.replace(/[\'\"\\\/]/gm, function (c) {
        return '\\' + c;
    });
});

您可以像这样调用您的助手:{{escapeJs title}}

var view = {
    title: "Joe's Lame\"\\/€"
};

var template = Handlebars.compile(
    "<a href=\"javascript:confirm('{{escapeJs title}}');\">{{title}}</a>");
var output = template(view);

fiddle中实时查看它。

Mustache非常酷,几乎可以在任何编程语言中使用。Handlebars很棒,例如在Backbone Thoraxassemble等强大的静态网站生成器中使用。

编辑:备选方案

当使用ECMAScript 5(并且通过shim/shiv/polyfills应该也可以在IE8上工作)时,可以按照以下方式为Mustache准备视图对象。我承认,这不是一个非常方便的解决方案,但是当产生JavaScript输出很少时,这可能是可以接受的。

function escapeJs (str) {
    return str.replace(/[\'\"\\\/]/gm, function (c) {
        return '\\' + c;
    });
}

var view = {
    title: "Joe's Lame"
};

Object.defineProperty(view, 'titleJsEnc', {
    enumerable: false,
    get: function () { return escapeJs(this.title); }
});

var output = Mustache.render(
    "<a href=\"javascript:confirm('{{titleJsEnc}}');\">{{title}}</a>", view);

通过 Object.defineProperty 定义一个新属性即可实现。可以编写一个通用的对象装饰器,为每个真实属性定义一个 getter,返回转义后的字符串值。

这里是fiddle

编辑:替代方案:等待 Mustache 的新版本

一旦pull-request被合并并发布了 Mustache 的新版本,这个问题就应该以“Mustache 本地方式”得到解决。


然而,当我评论说解决方案不一定非得是Mustache时,我并不是意味着它可以是任何技术。我想用我正在使用的技术之一来解决这个问题。 - Jason McCreary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接