Backbone: Firefoxで{trigger:false}の場合でも、URLにスペースを入れてnavigate()をトリガーするとルートがトリガーされます

作成日 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」がログに記録され、「Clickme」をクリックするたびに「click#」のログが記録されます。

ここで、小さな変更を1つ行います。 ナビゲート()のURLにスペースを追加します。

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

もう一度やり直すと、その「ホームルート:#」もログに記録され始め、カウンターは_3回のクリックごとに2回_リセットされます。

これは1.1.2リリースにあり、最新のFirefox33.1でテストしています。 Chromeではこの問題は発生していません。ChromeがURLのスペースをエンコードするために何かを行っている可能性があります。 でもわかりません。

そもそもスペース文字をURLに含めるべきではないことは理解していますが、この動作は奇妙であり、少なくとも文書化する必要があります。 (つまり、「navigate()は、スペース(またはその他の安全でない文字??)を含むURLでは期待どおりに動作しない可能性があります。」)

これを簡単に修正できるかどうかはわかりませんが、少なくともこのバグを文書化することで、他の開発者がそれを探し出す時間を節約できることを願っています。

invalid

最も参考になるコメント

これが私が発見したものです。 Firefoxでは、変数「this.location.href」をチェックすると、変数内の空白はすべて%20にエンコードされます。 Chrome(およびおそらくIE)は、それらを空白として残します。 これはバックボーンの問題です。ナビゲートするときに、「checkUrl()」が「this.fragment」と「this.getFragment()」の戻り値を比較して、「this」を呼び出すかどうかを判断するためです。 loadUrl() "、一致しない場合。 this.getFragment()は、this.location.hrefの値を返します。Firefoxのスペース(またはそれに関するエンコーディング)の代わりに%20が使用されます。 this.fragmentは、デコードされた同等のものを返します。 this.fragmentは、URLでencodeURI()を使用するかどうかに関係なく、デコードされたままになります。これは、「navigate()」関数で、渡されるURLで「this.decodeFragment()」を呼び出すことによってthis.fragmentが割り当てられるためです。で、エンコードを強制する試みを削除します。

したがって、this.fragmentがthis.decodeFragment()の使用により常にデコードされたURLであり、URLにencodeURI()が変更する文字(この場合はスペース)が含まれている場合、thisの戻り値と一致することはありません。 Firefoxでは.getFragment()。Firefoxはthis.location.hrefの値をエンコードしますが、他のブラウザはエンコードしません。 これらの2つの値は一致しないため、router.navigateのトリガーパラメーターがtrueまたはfalseであるかどうかに関係なく、this.loadUrl()がcheckUrl()で呼び出されます。

予備的な修正(徹底的なテスト)は、「getHash()」メソッドの戻り値を次のように変更することです。

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

全てのコメント8件

こんにちは@chaimpeck! これを報告していただきありがとうございます。

残念ながら、上記のコードを使用して再現することはできませんでした。 マスターブランチと1.1.2リリースの両方で最新のChromeとFirefoxを試しました。 私が見ることができる要点/ビン/フィドルに実用的な例を投稿していただけませんか?

Firefoxで特定の文字をエンコード/デコードする際に問題が発生したことは間違いありませんが、他にも問題があることは間違いありません。 :スマイリー:

私は実際にこれとまったく同じ問題を見ましたが、私のコードを共有することができません。 これを複製するためにいくつかのテストコードをモックアップできるかどうかを確認しますが、問題は間違いなくブラウザベースであることがわかりました。 IEとChromeの最新バージョンはすべて正常に動作しますが、少なくともFirefox v31.5.0では(質問しないでください。私たちが立ち往生しているインフラストラクチャは嫌いです)、トリガーオプションを追加しなくても確実にトリガーされます。

これが私が発見したものです。 Firefoxでは、変数「this.location.href」をチェックすると、変数内の空白はすべて%20にエンコードされます。 Chrome(およびおそらくIE)は、それらを空白として残します。 これはバックボーンの問題です。ナビゲートするときに、「checkUrl()」が「this.fragment」と「this.getFragment()」の戻り値を比較して、「this」を呼び出すかどうかを判断するためです。 loadUrl() "、一致しない場合。 this.getFragment()は、this.location.hrefの値を返します。Firefoxのスペース(またはそれに関するエンコーディング)の代わりに%20が使用されます。 this.fragmentは、デコードされた同等のものを返します。 this.fragmentは、URLでencodeURI()を使用するかどうかに関係なく、デコードされたままになります。これは、「navigate()」関数で、渡されるURLで「this.decodeFragment()」を呼び出すことによってthis.fragmentが割り当てられるためです。で、エンコードを強制する試みを削除します。

したがって、this.fragmentがthis.decodeFragment()の使用により常にデコードされたURLであり、URLにencodeURI()が変更する文字(この場合はスペース)が含まれている場合、thisの戻り値と一致することはありません。 Firefoxでは.getFragment()。Firefoxはthis.location.hrefの値をエンコードしますが、他のブラウザはエンコードしません。 これらの2つの値は一致しないため、router.navigateのトリガーパラメーターがtrueまたはfalseであるかどうかに関係なく、this.loadUrl()がcheckUrl()で呼び出されます。

予備的な修正(徹底的なテスト)は、「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] : "" }

@Aggror pathStripperは、ドキュメントによると、ハッシュのURLを削除するためのキャッシュされた正規表現です。

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

したがって、これはソリューションと同等であり、より適切で効率的です:)

ルーターに同じハッシュを同時に追加することは避け、初期条件にも注意してください。コードを表示します
(最初のケースを処理するため)(同じルートが同時に追加されないようにするため)
if(routes.length === 1 || routes [routes.length-1] === getHash()){
falseを返します。
}
そうしないと{
ルート.push(getHash())
};

このページは役に立ちましたか?
0 / 5 - 0 評価