【问题标题】:Backbone.js navigation working once but not againBackbone.js 导航工作一次但不再工作
【发布时间】:2012-04-17 01:15:34
【问题描述】:

我正在使用 Backbone-on-rails gem 中的 Backbone.js 0.9.2。我也在尝试使用新的“pushState”而不是旧的哈希 URL。

问题

我正在构建一个像 CRUD 一样的标准 Rails 界面来跟踪我的约会。我在 index.jst.eco 主页面上有一个“新”链接:

<h1>Appointments</h1>
<p><a href="/appointments/new" class="new">New Appointment</a></p>

我加载页面并单击“新”链接,主干会触发该事件,而不必重新加载整个页面。这是那个事件:

class BackboneOnRails.Views.AppointmentsIndex extends Backbone.View
  template: JST['appointments/index'],
  events: ->
    'click .new': 'newAppointment'

  newAppointment: ->
    Backbone.history.navigate("/appointments/new", {trigger: true})
    return false

  # The rest of the index methods omitted for brevity 

然后调用主干路由器:

class BackboneOnRails.Routers.Appointments extends Backbone.Router
  routes:
    '': 'index'
    'appointments': 'index'
    'appointments/new': 'new'

  initialize: ->
    this.appointments = new BackboneOnRails.Collections.Appointments()
    this.appointmentsIndexView = new BackboneOnRails.Views.AppointmentsIndex({collection: this.appointments})
    this.appointmentsIndexView.render()

  index: ->
    $("#container").html(this.appointmentsIndexView.el)
    this.appointments.fetch()

  new: ->
    appointments = new BackboneOnRails.Collections.Appointments()
    view = new BackboneOnRails.Views.AppointmentNew({collection: appointments})
    $("#container").html(view.render().el)

当我点击浏览器的返回按钮,然后再次尝试使用“新”链接时,就会出现问题。这一次它会完全重新加载页面。

当我回击浏览器时,javascript 绑定发生了什么?

我有一个项目的表演活动,我可以来回走动没有问题。我已经比较了两者,它们看起来像是同一种调用。

【问题讨论】:

    标签: backbone.js coffeescript


    【解决方案1】:

    问题在于您尝试重复使用约会索引视图实例。从 DOM 中删除视图会破坏 DOM 事件处理程序。将视图的 el 重新添加到 DOM 不会重新连接它们。

    问题概述

    当您第一次使用路由器的 initializeindex 方法加载该视图时,一切都很好,因为您有一个新的 IndexView 实例。 DOM 事件正确地附加到视图上,生活很好。

    当您点击路由器的new 路由/方法时,您实际上是在尝试从屏幕上删除索引视图并将其替换为添加新视图。从视觉角度和添加新视图的角度来看,这是可行的。

    但是,当您点击后退按钮时,您将停留在浏览器选项卡中的同一个实时应用程序实例中。在启用 pushstate 的情况下点击后退按钮告诉浏览器不要重新加载整个应用程序,只是为了更新 url 并触发索引的路由器方法。

    在这种情况下,您的索引视图不是从头开始重新构建的。您正在重新使用相同的视图实例,但使用来自服务器的数据重新加载它。数据加载工作得非常好,因为您的视图和集合仍然附加。但是,DOM 事件绑定失败了,因为它们的绑定之前已被移除且未重新添加。

    2 常见解决方案

    对此有两种常见的解决方案,以及这些解决方案的许多变体。

    1) 不要重复使用视图实例。

    这是我强烈推荐的建议。在我尝试重用视图实例的每个实例中,我一直遇到非常大的问题 - 包括您遇到的确切问题。

    相反,每次需要显示约会索引时都重新创建一个新视图实例。这意味着您在路由器的index 方法中创建新的索引视图,而不是initialize 方法。

    2) 清除并重新绑定 DOM 事件

    如果出于某种原因,您觉得您确实需要重用视图实例(这绝不应该是真的),您可以使用 Tim Branyen 不久前在他的博客上发布的一些信息来解决它:

    http://tbranyen.com/post/missing-jquery-events-while-rendering

    我不推荐这种方法。重新使用视图实例似乎是一个好主意,但它会导致其他问题的出现,包括由于在应用程序中留下太多未使用的部分而导致内存使用膨胀。

    旁注:僵尸和内存泄漏

    在任何一种情况下 - 无论您决定重用视图实例还是在需要时重新创建它们 - 您都可能会遇到一些内存泄漏。

    在重用视图的情况下,当您不需要时,您会明确地保留内存中的对象。这并不是真正的“泄漏”,而是过度使用内存。您应该在不需要时取消引用该对象,并在需要时重新创建它。这将减少内存使用并让您的应用程序性能更好。

    我有一篇博客文章介绍了它是如何工作的,在这里:http://lostechies.com/derickbailey/2012/03/19/backbone-js-and-javascript-garbage-collection/

    在不重用视图的情况下,您可能会在视图从可见 DOM 中删除后留下模型和集合事件绑定,从而导致真正的内存泄漏。如果您决定不重用您的视图,则需要使替换 #container html 的代码更加健壮,并让它清理旧视图。

    我也有一篇博文详细介绍了解决方案:http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/ - 请务必阅读本文中 Johnny Oshika 的 cmets,因为他指出了一个非常有用的 StackOverflow 答案,其中他展示了一个简单的处理模型和集合事件的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-02
      相关资源
      最近更新 更多