【问题标题】:Preventing full page reload on Backbone pushState防止在 Backbone pushState 上重新加载整页
【发布时间】:2011-11-30 05:17:34
【问题描述】:

我正在尝试使用 Backbone 的 pushState 防止整个页面重新加载。当我从视图的事件中调用 navigate() 时,我看到下面标记为 // 1 的消息,但没有看到 // 2。此外,当我尝试打开同一个选项卡时,页面会再次重新加载。

我必须自己停止活动吗?我尝试使用 jQuery 的 preventDefault(),它确实可以防止页面重新加载,但我还没有在任何地方看到这个文档。

以下是我当前的代码:

App.Router = Backbone.Router.extend({
  routes:{
      "analytics":"analytics"
    , "realtime":"realtime"
  }

  , analytics:function(page) {
    console.log("analytics route hit: %o", page); // 2
  }

  , realtime:function(page) {
    console.log("realtime route hit: %o", page); // 2
  }
});

App.TabSetView = Backbone.View.extend({
  initialize:function() {
    this.collection.bind("reset", this.render, this);
    this.collection.bind("add", this.render, this);
    this.collection.bind("change", this.render, this);
    this.collection.bind("remove", this.render, this);
  }

  , events:{
      'click li.realtime a':  "onRealtime"
    , 'click li.analytics a': "onAnalytics"
  }

  , render:function() {
    // omitted for brevity
  }

  , onAnalytics:function() {
    console.log("onAnalytics"); // 1
    if (this.collection.activateAnalytics()) {
      App.app.navigate("analytics", true);
      this.render();
      console.log("navigated");
    } else {
      console.log("do nothing"); // 1
    }
  }

  , onRealtime:function() {
    console.log("onRealtime");
    if (this.collection.activateRealtime()) {
      App.app.navigate("realtime", true);
      this.render();
      console.log("navigated");
    } else {
      console.log("do nothing"); // 1
    }
  }
});

var tabs = ...; // omitted for brevity
var tabSetView = new App.TabSetView({collection: tabs});
var App.app = new App.Router;
Backbone.history.start({pushState:true});

【问题讨论】:

    标签: backbone.js


    【解决方案1】:
     $('a').click(function(e){
       e.preventDefault();
       Backbone.history.navigate(e.target.pathname, {trigger: true});
     });
    

    【讨论】:

    • 外部链接呢?
    • 在锚点上使用数据属性或类来排除外部链接并相应地更新选择器处理程序。稍后我会更新示例。
    【解决方案2】:

    只是对 Derick 回答的跟进。 它对我有用,但为了保持干净,我重写了 Backbone.View 类:

    (咖啡脚本)

    class NewBackboneView extends Backbone.View
      events:
        'click a' : 'pushstateClick'
    
      pushstateClick: (event) ->
        event.preventDefault()
    
      Backbone.View = NewBackboneView
    

    所以我的主干视图中的每个链接都有阻止默认值。

    【讨论】:

      【解决方案3】:

      答案实际上在这里https://stackoverflow.com/a/9331734/985383,如果您启用pushState,您希望链接正常工作而不是按照上面的建议阻止它们,或者不仅仅是阻止它们。在这里:

      initializeRouter: function () {
        Backbone.history.start({ pushState: true });
        $(document).on('click', 'a:not([data-bypass])', function (evt) {
      
          var href = $(this).attr('href');
          var protocol = this.protocol + '//';
      
          if (href.slice(protocol.length) !== protocol) {
            evt.preventDefault();
            app.router.navigate(href, true);
          }
        });
      }
      

      【讨论】:

      • href.slice(protocol.length) 应该是 href.slice(0, protocol.length) 或 href.substr(0, protocol.length) 否则你没有检查你正在使用的协议检查之后的所有内容。
      • 其实,我认为的目的是将href中协议之后的所有内容与协议进行比较,但不清楚为什么。请问有人可以赐教吗?
      • 自言自语——这是为了确保链接是相对的,即不以协议开头。
      【解决方案4】:

      要在用户单击链接时停止页面重新加载,您必须按照您的建议致电 e.preventDefault()

      
      MyView = Backbone.View.extend({
        events: {
          "click .some a": "clicked"
        },
      
        clicked: function(e){
          e.preventDefault();
          // do your stuff here
        }
      });
      

      您也说得对,骨干文档中没有记录。不过,事件由 jQuery 处理。所以你可以假设你会做的任何有效的 jQuery 事情——比如有一个事件回调的e 参数——都可以与主干的events 一起工作。

      至于这个:

      此外,当我尝试打开同一个选项卡时,页面会再次重新加载。

      您是说当用户打开一个新的浏览器选项卡到您网站的 URL 时?如果是这样,那么您对此无能为力。当浏览器打开选项卡时,它会向服务器发出加载页面的请求。

      但是,如果您将“标签”作为您网站用户界面的一部分,那么在您的链接/“标签”点击中使用 e.preventDefault() 应该可以解决这个问题。

      【讨论】:

      • 请注意,如果视图没有定义 el,此解决方案将不起作用。例如: var view = Backbone.View.extend({el: $("#anElement"), etc..});
      【解决方案5】:

      这取决于您如何生成 HTML 标记。看起来您正在使用锚标签 (<a>),因此如果这些锚标签 href 有值甚至是空字符串,那么您需要取消默认浏览器行为,否则您将重新加载页面。您可以使用 jQuery're event.preventDefault() 取消默认行为,就像您提到的那样。或者,如果您不关心渐进增强或 SEO,那么您可以将锚标记 href 设置为 # 或 javascript:void(0);,这也将阻止页面重新加载。例如

      <a href="#">Click me</a>
      

      <a href="javascript:void(0);">Click me</a>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-04
        • 1970-01-01
        • 2014-04-16
        • 2013-09-05
        相关资源
        最近更新 更多