我的Backbone应用程序中有一个电子邮件视图。它目前在我的控制器的view
操作中实例化。它有点像这样:
routes: {
'email/:id': email
},
//...
email: function (id) {
var email = new Email({
id: id
});
this.emailView = new EmailView({
model: email
});
email.fetch();
}
现在,问题是,如果我访问一封电子邮件,那么我最终会创建两个单独的EmailView
。这意味着,例如,EmailView
中的删除链接绑定到两个单独的Email
模型,因此单击删除将删除两者(不是一件好事)。
我正在寻找两种解决方案。在其中一个,我将缓存EmailView
,并更新其模型。那么问题是我必须重新绑定events
中的EmailView
。
另一种解决方案是像我现在一样创建一个新的EmailView
,但在替换它之前解除旧的EmailView.el
事件的绑定。
我是以正确的方式来做这件事的吗?有没有更好的方法来处理这种情况?提前干杯。
答案 0 :(得分:3)
为每个模型实例创建单独的视图实例。每次您访问新电子邮件时,都会丢弃旧视图并使用新的电子邮件实例创建新视图。
如果我猜的是你左边的列表视图和右边的编辑器,你可能拥有的东西。您可以从左侧列表中选择电子邮件,并希望电子邮件正文显示在右侧。
你真的想要5个视图类。
PageView
has_one EmailCollectionView on left
has_one EmailEditorView on right
EmailCollectionView
has_many EmailSummaryViews as vertical list
EmailEditorView
has_one EmailView centered
当您在EmailCollectionView中单击时,您会触发一个事件 通过EmailEditorView获取,它抛弃了它的旧版EmailView 并呈现新版本的EmailView
无论如何这样的东西答案 1 :(得分:2)
每当有人导航到例如,我们最初都会创建新的视图对象。 “候选人/节目”,就像电子邮件示例一样。该视图将处理程序绑定到其持久性模型的“重置”事件。当我们从命令行重置该模型时,我们会看到与该视图的实例一样多的事件。换句话说,即使添加到DOM中的元素都被完全破坏,该视图也不会被垃圾收集。
我们的解决方案是确保一次实例化我们的顶级视图,然后让他们在初始化方法中创建子视图。然后根据需要重新渲染它们。然后你不必担心垃圾收集的复杂性(就我从实验中可以看出,无论如何都不会发生)。
答案 2 :(得分:2)
我认为应该通过调用视图的remove()方法来删除DOM事件处理程序 - 请参阅http://api.jquery.com/remove(Backbone调用的内容)
如果重写remove()方法以删除对JohnnyO建议的任何模型事件的绑定,则垃圾收集应该负责删除视图。
我最终覆盖了remove()方法来处理这个问题:
class EmailView extends Backbone.View
initialize: () ->
@model.bind('change', @render)
render: () =>
# do some stuff
remove: () ->
@model.unbind('change', @render)
super()
然后您可以在路由器中使用:
routes:
'email/:id': email
//...
email: (id) ->
var email = new Email({
id: id
});
this.emailView.remove() if this.emailView
this.emailView = new EmailView({
model: email
});
email.fetch();
}
这将假设视图中的所有事件都绑定到正确的元素 - 也就是说,您在视图中使用@el(或this.el)并且每个视图都有自己的@ el / this .el。