当我将新URL推送到Backbone.history时,查询参数保持不变?

时间:2013-03-01 19:48:32

标签: javascript html5 url backbone.js pushstate

假设我使用Backbone pushstate并导航到带有查询参数的页面:

domain.com/user/111?hello=123

执行此操作时:

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

我的设置页面加载完美,但?hello = 123保留在URL ...

domain.com/settings?hello=123

该查询参数保留在我浏览网站的任何地方的URL中......

3 个答案:

答案 0 :(得分:19)

骨干路由和查询参数是一段不愉快的婚姻。问题在this GitHub issue中有详细记录。

核心问题是Backbone.Router旨在处理URL哈希片段以及pushState API。使用散列URL时,查询字符串位于散列之前,并且在路由中永远不会匹配。使用pushState,查询字符串是URL片段的一部分,并且需要不同的路由表达式。

假设您有一条路线search,该路线可选择参数qsorttype。作为查询字符串,看起来像:

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

问题是,对于旧浏览器的用户,Backbone将恢复为基于hashchange的路由,路由将变为:

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

您使用的插件会尝试解决此问题,但无法解决核心问题。

如果可能,您应该考虑不使用查询字符串,并使用路由表达式中的可选片段传递任何状态信息。之前的示例路由将变为:

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

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

使用(optional)路径部分和:capturesdocs),您可以使用以下表达式表示此网址:

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" 
  }
});

只要路径片段符合指定的顺序,这将使url与none,any和all参数匹配,例如:

search                       //->  undefined,  undefined, undefined
search/q/kittens/type/images //->  "kittens",  undefined, "images"
search/sort/asc/type/images  //->  undefined,  "asc",     "images"

这样您就不必担心第三方查询字符串库或浏览器兼容性。如果你问我,后一种类型的URL看起来也更清晰。

答案 1 :(得分:2)

您不必再使用backbone-query-parameters插件来处理此问题,只需确保您拥有最新版本的Backbone,然后覆盖loadUrl内的History.prototype方法

// 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;
},

答案 2 :(得分:0)

不确定是否为时已晚。我遇到了同样的问题,我可以自信地说出来:这是一个由骨干查询参数引起的错误。

我的灵感来自你的帖子。在我当前项目的早期阶段,我介绍了backbone-query-parameters,它运行良好。但是后来,骨干进行了一些更改,因此骨干查询参数不再能够抓取参数。直到最近,我才发现作者升级了backbone-query-parameters。我再次把它拉进来,它起作用了。

然后,你知道。我提出同样的问题并感到非常沮丧。我从不怀疑骨干查询参数,直到我看到你的帖子。

我删除了插件并配备了我自己的代码,现在我的历史就像一个魅力。

有很多方法可以获取get参数。我只是其中之一,但它对我有用。仅供参考,我在这里发布。

  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

以防万一,我的路线会是这样的

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