Backbone: 即使在 Firefox 中使用 {trigger:false} 时,URL 中带有空格的导航()也会触发路由

创建于 2014-11-27  ·  8评论  ·  资料来源: jashkenas/backbone

考虑这个例子:

$(function(){
var AppRouter = Backbone.Router.extend({

    routes: {
        '(count/:count)': 'home',
    },

    home: function(currCount) {
        var counter = 0;
        var thisObj = this;

        $("body").html($("<p>Click me</p>").on('click', function() {
            console.log("clicked "+counter);
            counter++;
            thisObj.navigate('count/'+counter, {trigger:false, replace: true});
        }));

        console.log('home route: '+currCount);    
    },
});

window.app = new AppRouter();
Backbone.history.start();
});

这应该记录“home route: null”,然后为每次点击“Click me”记录“click #”。

现在,做一个小的修改。 在 navigate() 中为 url 添加一个空格:

thisObj.navigate('count/ '+counter, {trigger:false, replace: true});

再试一次,您会发现“home route:#”也将开始被记录,并且计数器将重置_每三次点击中的两次_。

这是 1.1.2 版本,我正在最新的 Firefox 33.1 上进行测试。 我在 Chrome 中没有这个问题 - 这可能是因为 Chrome 可能会对 URL 中的空格进行编码。 不过我不确定。

我意识到空格字符首先不应该出现在 URL 中,但是这种行为很奇怪,至少应该记录在案。 (即“对于包含空格(或其他不安全字符??)的 URL,navigation() 的行为可能与预期不同。”)

我不确定是否有一个简单的解决方案,但我希望至少通过记录这个错误,我可以节省其他开发人员尝试寻找它的时间。

invalid

最有用的评论

这是我发现的。 在 Firefox 中,如果您检查变量“this.location.href”,变量中的任何空格都会被编码为 %20。 Chrome(可能是 IE)将它们保留为空白。 这是 Backbone 中的一个问题,因为当您导航时,“checkUrl()”会将“this.fragment”与“this.getFragment()”的返回值进行比较,以确定是否调用“this.fragment”。 loadUrl()",如果它们不匹配。 this.getFragment() 返回 this.location.href 的值,用 %20 代替 Firefox 中的任何空格(或任何编码)。 this.fragment 返回解码后的等价物。 this.fragment 保持解码,无论您是否在 URL 上使用 encodeURI(),因为在“navigate()”函数中,this.fragment 是通过在传递的 URL 上调用“this.decodeFragment()”来分配的in,删除任何强制编码的尝试。

因此,如果由于使用 this.decodeFragment() 而 this.fragment 始终是一个解码的 URL,并且 URL 包含 encodeURI() 会改变的任何字符(在这种情况下为空格),它永远不会匹配 this 的返回值.getFragment() 在 Firefox 中,因为 Firefox 会编码 this.location.href 的值,而其他浏览器则不会。 由于这两个值不匹配,因此无论 router.navigate 中的触发参数是真还是假,都会在 checkUrl() 中调用 this.loadUrl()。

初步修复(预详尽测试)是将“getHash()”方法的返回值更改为:

return match ? this.decodeFragment(match[1].replace(pathStripper, '')) : '';

所有8条评论

嗨@chaimpeck! 感谢您报告此事。

不幸的是,我无法使用上面的代码重现它。 我在 master 分支和 1.1.2 版本中尝试了最新的 Chrome 和 Firefox。 您介意在 gist/bin/fiddle 中发布一个我可以查看的工作示例吗?

我们之前肯定在 Firefox 中编码/解码特定字符时遇到过问题,我不会怀疑还有更多。 :笑脸:

我实际上已经看到了这个完全相同的问题,但我无法分享我的代码。 我会看看我是否可以模拟一些测试代码来复制它,但我发现这个问题肯定是基于浏览器的。 所有现代版本的 IE 和 Chrome 都可以正常工作,但至少在 Firefox v31.5.0 上(别问,我讨厌我们坚持的基础设施),它肯定会触发,甚至不需要添加触发选项。

这是我发现的。 在 Firefox 中,如果您检查变量“this.location.href”,变量中的任何空格都会被编码为 %20。 Chrome(可能是 IE)将它们保留为空白。 这是 Backbone 中的一个问题,因为当您导航时,“checkUrl()”会将“this.fragment”与“this.getFragment()”的返回值进行比较,以确定是否调用“this.fragment”。 loadUrl()",如果它们不匹配。 this.getFragment() 返回 this.location.href 的值,用 %20 代替 Firefox 中的任何空格(或任何编码)。 this.fragment 返回解码后的等价物。 this.fragment 保持解码,无论您是否在 URL 上使用 encodeURI(),因为在“navigate()”函数中,this.fragment 是通过在传递的 URL 上调用“this.decodeFragment()”来分配的in,删除任何强制编码的尝试。

因此,如果由于使用 this.decodeFragment() 而 this.fragment 始终是一个解码的 URL,并且 URL 包含 encodeURI() 会改变的任何字符(在这种情况下为空格),它永远不会匹配 this 的返回值.getFragment() 在 Firefox 中,因为 Firefox 会编码 this.location.href 的值,而其他浏览器则不会。 由于这两个值不匹配,因此无论 router.navigate 中的触发参数是真还是假,都会在 checkUrl() 中调用 this.loadUrl()。

初步修复(预详尽测试)是将“getHash()”方法的返回值更改为:

return match ? this.decodeFragment(match[1].replace(pathStripper, '')) : '';

仍然需要上一个版本,所以谢谢!

尝试在 URL 中使用非标准字符时,我遇到了同样的问题,在我的例子中是 åäö(瑞典字母表中的字符)。 最新版本的 Chrome 和 Backbone。

sjmiller85 的解决方案也对我有用。 非常感谢!

@sjmiller85你的解决方案是什么? 我不完全理解“pathStripper”应该使用什么。 这是一个正则表达式吗?
编辑:这在我的情况下有效。 见https://github.com/jashkenas/backbone/pull/3955/files
getHash: function (t) { var e = (t || this).location.href.match(/#(.*)$/); return e ? e[1] : "" }

根据文档, @Aggor pathStripper 是一个缓存的正则表达式,用于剥离散列的 url。

// Cached regex for stripping urls of hash.
var pathStripper = /#.*$/;

所以它相当于你的解决方案,只是更整洁和高效:)

避免同时向您的路由器添加相同的哈希值并注意初始条件,我将向您展示代码
(处理初始情况)(防止同时添加相同的路由)
if ( routes.length === 1 || routes[routes.length-1] === getHash() ) {
返回假;
}
别的{
routes.push(getHash())
};

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

tribalvibes picture tribalvibes  ·  11评论

rubiii picture rubiii  ·  12评论

gfranko picture gfranko  ·  18评论

jonathan picture jonathan  ·  11评论

omenking picture omenking  ·  10评论