Backbone.js导航工作一次,但不能再次工作
我正在使用rails上的主干gem中的Backbone.js 0.9.2。我还尝试使用新的“pushState”而不是旧的散列URL 问题 我正在构建一个类似于CRUD的标准Rails界面来跟踪我的约会。我在主index.jst.eco页面上有一个“新”链接:Backbone.js导航工作一次,但不能再次工作,backbone.js,coffeescript,Backbone.js,Coffeescript,我正在使用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></
<h1>Appointments</h1>
<p><a href="/appointments/new" class="new">New Appointment</a></p>
然后调用主干路由器:
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绑定发生了什么变化
我有一个展示活动的项目,我可以去来回没有问题。我将两者进行了比较,它们看起来像是相同类型的调用。问题在于您试图重新使用appointmentsIndexView实例。从DOM中删除视图会破坏DOM事件处理程序。将视图的
el
重新添加到DOM不会重新连接它们
问题概述
当您第一次使用路由器的initialize
和index
方法加载该视图时,一切正常,因为您有一个新的IndexView实例。DOM事件被正确地附加到视图中,生活是美好的
当您点击路由器的new
route/method时,您实际上是在试图从屏幕上删除索引视图,并将其替换为addnew视图。这是从视觉角度和“添加新视图”的角度进行的
但是,当您点击后退按钮时,您将停留在浏览器选项卡中的同一个实时应用程序实例中。在启用pushstate的情况下点击back按钮,告诉浏览器不要重新加载整个应用程序,只需更新url并启动索引的router方法即可
在这种情况下,您会发现索引视图不是从头开始重新构建的。您使用的是同一个视图实例,但从服务器重新加载数据。数据加载工作得非常好,因为您的视图和集合仍处于连接状态。但是,DOM事件绑定失败,因为它们的绑定以前已被删除,而没有重新添加
2共同解决方案
有两种常见的解决方案,以及这些解决方案的许多变体
1) 不要重复使用视图实例。
这是我强烈推荐的建议。在我尝试重用视图实例的每一个实例中,我都会遇到非常大的问题,包括您遇到的确切问题
而是在每次需要显示约会索引时重新创建一个新的视图实例。这意味着您可以在路由器的index
方法中创建新的索引视图,而不是initialize
方法
2) 清除并重新绑定DOM事件
如果出于某种原因,您觉得确实需要重新使用view实例(这永远不会是真的),您可以使用Tim Branyen不久前在其博客上发布的一些信息来解决这个问题:
我不推荐这种方法。立即重新使用视图实例似乎是个好主意,但它会导致其他问题的出现,包括在应用程序中留下太多未使用的部分导致内存使用过多
旁注:僵尸和内存泄漏
在这两种情况下,无论您是决定重用视图实例还是在需要时重新创建它们,您都可能会遇到一些内存泄漏
在重复使用视图的情况下,您在不需要时显式地保留内存中的对象。这不是真正的“泄漏”,而是内存的过度使用。您应该在不需要时取消引用对象,并在需要时重新创建它。这将减少内存使用,让你的应用程序运行得更好
我在这里发布了一篇博客文章,介绍了这是如何工作的:
在不重用视图的情况下,从可见DOM中删除视图后,可能会留下模型和集合事件绑定,从而导致真正的内存泄漏。如果决定不重复使用视图,则需要使替换#容器的代码更加健壮,并让它清理旧视图
我有一篇博客文章详细介绍了解决方案:-一定要阅读Johnny Oshika在这篇文章中的评论,因为他指出了一个非常有用的StackOverflow答案,其中他展示了一种处理模型和收集事件的简单方法。问题在于您试图重新使用appointmentsIndexView实例。从DOM中删除视图会破坏DOM事件处理程序。将视图的el
重新添加到DOM不会重新连接它们
问题概述
当您第一次使用路由器的initialize
和index
方法加载该视图时,一切正常,因为您有一个新的IndexView实例。DOM事件被正确地附加到视图中,生活是美好的
当您点击路由器的new
route/method时,您实际上是在试图从屏幕上删除索引视图,并将其替换为addnew视图。这是从视觉角度和“添加新视图”的角度进行的
但是,当您点击后退按钮时,您将停留在浏览器选项卡中的同一个实时应用程序实例中。在启用pushstate的情况下点击back按钮,告诉浏览器不要重新加载整个应用程序,只需更新url并启动索引的router方法即可
在这种情况下,您会发现索引视图不是从头开始重新构建的。您使用的是同一个视图实例,但从服务器重新加载数据。数据加载工作得非常好,因为您的视图和集合仍处于连接状态。但是,DOM事件绑定失败,因为它们的绑定以前已被删除,而没有重新添加
2共同解决方案
对于这一点,有两种常见的解决方案,还有许多不同的解决方案
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)