2013-03-01 4 views
13

Sagen wir, ich bin Backbone pushstate verwenden und ich navigieren Sie zu einer Seite mit Abfrage params:Wenn ich eine neue URL nach Backbone.history verschiebe, bleiben die Abfrageparameter erhalten?

domain.com/user/111?hello=123 

Als ich dies ausführen:

Backbone.history.navigate('/settings', true); 

perfekt Meine Einstellungen Seite geladen wird, aber das hallo =? 123 Aufenthalte in der URL ...

domain.com/settings?hello=123 

Und die Abfrage param Aufenthalte in der URL überall navigieren ich die Website ...

+0

bearbeiten sein: Ich habe das https://github.com/jhudson8/backbone-query-parameters Plugin verwenden. – TIMEX

+0

Könnten Sie die Frage ein wenig klarer machen? Sie möchten die 'location.search' immer löschen, wenn Sie zu einer anderen Seite navigieren? –

+0

Es scheint, ein Problem vor etwa 2 Tagen auf [Github] (https://github.com/jhudson8/backbone-query-parameters/issues/29) gepostet und der Autor scheint nicht an dieser Funktion gearbeitet haben. – Starx

Antwort

19

Backbone Routing und Abfrageparameter sind eine unglückliche Ehe. Probleme sind in this GitHub issue gut dokumentiert.

Das Kernproblem ist, dass Backbone.Router entworfen wird, um mit URL-Hash-Fragmenten sowie der PushState-API zu arbeiten. Bei der Verwendung von Hash-URLs steht die Abfragezeichenfolge vor dem Hash und wird in der Route nie abgeglichen. Mit pushState ist die Abfragezeichenfolge Teil des URL-Fragments und erfordert einen anderen Routenausdruck.

Angenommen, Sie search eine Route haben würde, und dass Routenparameter optional q, sort und type nehmen würde. Als Query-String, der etwas aussehen würde:

search?q=kittens&sort=asc&type=images 

Das Problem ist, dass für die Nutzer von älteren Browsern, wird Backbone zu hashchange based Routing zurückkehren, und die Route wird geworden:

?q=kittens&sort=asc&type=images#search 

Die Plug-in, das Sie verwenden, versucht, dieses Problem zu umgehen, löst das Kernproblem jedoch nicht.

Wenn möglich, sollten Sie in Betracht ziehen, keine Abfragezeichenfolgen zu verwenden und keine Statusinformationen mit optionalen Fragmenten in den Routenausdrücken zu übergeben. Die vorherige Beispiel Routen wären dann:

//pushState 
search/q/kittens/sort/asc/type/images 

//hash fragment 
#search/q/kittens/sort/asc/type/images 

Mit (optional) Route Teilen und :captures (docs), können Sie diese URL mit dem folgenden Ausdruck darstellen könnten:

var Router = Backbone.Router.extend({ 
    routes: { 
    "search(/q/:query)(/sort/:sort)(/type/:type)": "search" 
    }, 

    search: function(query, sort, type) { 
    console.log(query, sort, type); //-> "kittens", "asc", "images" 
    } 
}); 

Solange die Strecke Fragmente sind in Die angegebene Reihenfolge entspricht URLs mit keinem, allen und allen Parametern, z. B .:

Dieser w Sie müssen sich keine Gedanken über die Abfragezeichenfolgenbibliotheken von Drittanbietern oder die Browserkompatibilität machen. Und wenn Sie mich fragen, sieht die letztere Art von URL auch sauberer aus.

+1

Denken Sie daran, zu viele Parameter in Schrägstrichen zu setzen, geht gegen die Prinzipien der RESTful-URL. Das Plus @ TIMEX-Problem wird durch das Plugin verursacht. Ich weiß, dass Backbone die Slash-Mode vorantreibt, aber ich denke, dass Style-Parameter zu bestimmten Funktionen passen, wie die beste Suche. – yujingz

+0

Schöne Lösung. Dies ist nur clientseitig, so dass die Idee von RESTful URLs hier sowieso nicht gilt. Jede funktionierende URL ist wirklich in Ordnung. – jasop

+0

@jasop stimme ich nicht zu. REST-konforme URLs sind nicht nur eine Frage der Implementierungsdetails. Sie sind auch Benutzer zugewandt und sollten idealerweise REST-konforme Standards einhalten, um Konsistenz im Web zu gewährleisten. Natürlich ist das hier ein recht gutartiger Bruch der REST-Konventionen. Ich sage nicht, dass es keine gültigen Begründungen für das Brechen von Konventionen gibt, nur dass die Tatsache, dass es sich um eine clientseitige URL handelt, nicht Teil der Begründung sein sollte. – acjay

2

Sie müssen das Plugin nicht mehr verwenden, um sicherzustellen, dass Sie über die neueste Version von Backbone verfügen und dann die loadUrl Methode in History.prototype überschreiben.

// Regex to match search query strings 
var searchStripper = /\?.*$/g; 

// Attempt to load the current URL fragment. If a route succeeds with a 
// match, returns `true`. If no defined routes matches the fragment, 
// returns `false`. 
loadUrl: function(fragmentOverride) { 
    var fragment = this.fragment = this.getFragment(fragmentOverride); 
    fragment = fragment.replace(searchStripper, ''); // remove the search query parameter 
    var matched = _.any(this.handlers, function(handler) { 
    if (handler.route.test(fragment)) { 
     handler.callback(fragment); 
     return true; 
    } 
    }); 
    return matched; 
}, 
+0

Entfernt dies nicht auch die URL-Parameter von der ursprünglichen URL 'user/111', wobei @TIMEX die Abfragekette vermutlich intakt halten soll? Es löst auch nicht das Problem, wenn Hash-basierte URLs verwendet werden, bei denen die Abfragezeichenfolge überhaupt nicht Teil des Fragments ist. – jevakallio

0

Nicht sicher, ob es zu spät ist. Ich bin auf das gleiche Problem gestoßen und kann es mit Zuversicht sagen: Es ist ein Bug, der durch Backbone-Abfrageparameter verursacht wird.

Ich habe tatsächlich von Ihrem Beitrag inspiriert. In der frühen Phase meines aktuellen Projekts habe ich Backbone-Abfrage-Parameter eingeführt, es hat gut funktioniert. Aber später hat Backbone einige Änderungen vorgenommen, so dass Backbone-Abfrage-Parameter die Parameter nicht mehr erfassen können. Erst kürzlich fand ich, dass der Autor Backbone-Abfrage-Parameter aktualisiert hat. Ich zog es wieder an und es funktionierte.

Dann wissen Sie. Ich habe das gleiche Problem und fühle mich wirklich frustriert. Ich habe nie an Backbone-Abfrage-Parametern gezweifelt, bis ich deinen Post gesehen habe.

Ich habe das Plugin entfernt und mit meinem eigenen Code ausgestattet, nun funktioniert meine Geschichte wie ein Zauber.

Es gibt zahlreiche Möglichkeiten, die get-Parameter abzurufen. Meins ist nur einer von ihnen, aber es macht den Job für mich. Nur für Ihre Referenz poste ich es hier.

getParams: -> 
    rtn = {} 

    if window.location.search.length > 0 
     queryStringRegex = /^\?(.*)/ 
     match = queryStringRegex.exec window.location.search 
     param_string = match[1] 

     if param_string.length > 0 
     params_array = param_string.split("&") 

     for value in params_array 
      temp = value.split("=") 
      rtn[temp[0]] = decodeURI(temp[1]) 

    rtn 

Nur für den Fall, meine Routen wie diese

"path(?*queryString)" : "pathAction"