Backbone.js - 嵌套视图是否应该保持对彼此的引用?

时间:2012-04-09 17:34:23

标签: backbone.js

如果Backbone View在其render()方法中创建了新视图,那么这些视图是否应该作为数据成员维护?典型的渲染方法如下:

render: function() {
  var myView = new MyView({ model: values });
  $('div#value', this.el).append(myView.render().el);
}

这种渲染方法的链接意味着嵌套的视图实际上只是创建,因此它也可以链接任何渲染方法并返回一个构造良好的元素。视图留给垃圾收集我假设?

如果要修改嵌套视图......可能很重要,是否应该(重新)创建,还是应该通过数据成员引用进行修改?

我遇到的问题是嵌套的视图接收事件,要求他们修改自己的嵌套视图,有时还要修改父视图。

我真的不想在各地开始投掷听众。传递对父视图的引用并从子视图调用render()会导致内存泄漏,因为父视图会创建一个新的子视图,而原始子视图会维护对其父视图的引用!

目前它不像框架那样。有没有人有任何资源可以帮助我以类似框架的方式解决这个问题?

1 个答案:

答案 0 :(得分:44)

(警告:我的回答变成了一篇论文;博士论文)

我在早期就遇到过一些相同的问题,为了构建一些相当复杂的应用程序而完成了我的作业,所以我会提供自己的观点。

学习骨干的一大挑战是,它是如此不受任何影响,并且可以(并且)以多种不同的方式使用,以至于很难弄清楚如何做某事"对"或者至少在你开始时以一种好的方式。使用骨干网并不是一种真正的方法,但它的灵活性使其成为几乎所有应用程序的绝佳结构,希望我能帮助提供一些指导。 (我可能会附上" IMO"到这里的每一句话。)

首先,我对骨干视图的理解

在主干应用中,有很多有用的方法可以使用视图。我通常会在我的应用中看到一些重叠的视图类型:

我通常有一个或多个" root-level"观点。根级视图通常是初始化,呈现和保持对处理页面特定部分的子视图的引用的地方。根级视图的el通常是" body"或身体内的另一个高级元素。在某些情况下,根级视图有自己的HTML来观察和/或渲染。在其他情况下,根级视图可能根本没有el,只管理子视图。我在全球应用程序中保留了对每个根级视图(通常只有一个)的引用。命名空间对象

除了" root-level"观点,通常有"子视图"。子视图由父母"初始化并呈现。视图,可以是根级视图或其他子视图。父视图负责按照应用程序的要求初始化,渲染,隐藏,显示和/或销毁他们的孩子。有时父视图可以跟踪子视图的可变数量的实例(例如,PlaylistView具有N个SongView)。通常,父母会保留对孩子的提及,但有时候这是不必要的(下面将详细介绍)。

除了根级/父级/子级'范式,我倾向于认为视图符合以下两个类别之一:(1)静态:意味着一旦视图被初始化,视图及其el就会一直存在,即使内部发生了变化; (2)基于各种事件来来去去的动态。通常,我的根级视图始终是静态的。它们通常也对应于现有的DOM元素,例如,' body'或者' #my-div'。子视图通常是动态的,但也可能是静态的。 (提示:在声明静态视图时,使用el: '#element-id'将现有DOM元素用作el。动态视图通常不指定现有el;他们使用tagName } idclassName来描述动态视图将生成的元素。)

视图基本上有3个功能:(1)当他们的父母或者响应事件时(或者在根级视图的情况下,当由路由器或&初始化时)呈现自己和他们的孩子。 #39; main'函数等),(2)通过更新模型或集合来响应来自el内的DOM元素的UI事件(但不在任何子视图的el内)或触发自定义Backbone事件,以及(3)观察并响应Backbone(模型,集合等)事件,这些事件需要在其内部呈现或更改(但不在任何子视图的内部)。有时 - 有用的技巧是子视图可以触发父视图可以观察到的事件(this.trigger('customEvent'))(childView.on('customEvent', this.handler, this))。

有关主干视图模式的其他有趣观点,请参阅:thisthis

现在在这种背景下,问题

1)害怕垃圾收集,范围和内存泄漏

如果您将子视图实例化为父级渲染(或其他)方法中的局部变量并渲染它,然后该函数超出范围,我可以理解您对垃圾收集的恐惧或者视图无法完成它需要做的事情。无需担心垃圾收集器,只需要僵尸。如果您的视图有任何事件处理程序,是否在"事件"中声明了UI事件处理程序。声明,或绑定到其他Backbone对象'事件或其他基于DOM的事件监听器,即使您不再引用它,您的视图也不会被垃圾收集 - 它仍将存在于内存中并响应事件。另一方面,如果一个视图没有任何事件处理程序,那么它唯一的工作就是渲染一个元素,所以谁关心渲染它的javascript对象是什么 - 它可能会被垃圾收集,因为它应该。请参阅this,了解js垃圾收集的一般情况以及它与Backbone.js的关系。

更大的担忧是Zombie views。如果要从DOM中删除视图并在应用程序中的某个时刻丢弃视图,请确保它们要么完全删除自己,要么父视图应该保留对它们的引用并将其删除。并且不要重新创建和替换已创建且未正确删除的视图。通过在视图上调用.remove()来解除删除,并使用on(...)解除您之前使用off(...)绑定的任何外部Backbone事件。 Backbone的最新版本(1.0+)通过将"listenTo" and "stopListening" methods添加到View原型,可以更轻松地解决此问题。如果您要在DOM中动态添加视图,请理解并使用这些方法而不是开/关。 提示:设置a hacky jquery "remove" event like this one可以轻松启用视图,以便在从DOM中删除el时自动删除和清理自己(如果事件没有发生在您的应用流程中,可以达到相同的目的。)

2)是否应将子视图维护为父视图的数据成员?

这取决于。我不认为家长的观点是出于有限的目的而意识到他们的孩子观点,这违反了MVC的任何黄金原则。有时,具有成员对特定子视图实例的引用的父级是在需要时管理子视图的好方法。正如我所指出的,有时父视图会响应需要它们渲染,重新渲染,隐藏或删除其子视图的事件。有时,他们可能想要听取儿童观点触发的事件。但是,父母不应该过多地参与他们孩子观点中的任何事情。 el但是。

尽管如此,不要过度使用这些类型的参考文献。很多时候,您不需要使用对儿童观点的引用,因为孩子们可以照顾好自己。正如我所提到的,视图一旦呈现,应该只有A)观察其内部的UI事件(但通常不在任何子视图中),并更新模型或集合或触发事件以响应这些UI事件,或者B)观察来自其他骨干对象(通常是模型或集合或其他视图)的事件,并采取行动(例如,更新他们自己的UI元素)作为响应。在许多情况下,视图可以自己处理,甚至可以自行删除。如果另一个View或其他Backbone对象关心视图中发生的UI事件,请更新模型或触发视图上的事件并让他们观察它。同样,如果视图外的某些内容需要在视图中更新渲染,请侦听模型的更改或等待相应的自定义事件。作为一般原则,观点应该是幸福地彼此不知道,除了父母在有意义的时候照顾他们的孩子。

3)子视图是否应保持对父视图的引用?

没有。决不。我不能想到一个单一的场景,你需要通过对父母的引用来完成某些事情,而父母无法通过改变父母正在观察的模型或触发事件来完成(例如,一个自定义事件说"嘿,X发生了#34;)关于子视图本身或另一个主干"基于事件"的对象。在Backbone中,我使用模型来表示我的数据和我的状态。因此,如果某个视图中的某些内容发生了更改我的应用程序的状态,那么我会更改模型的相应状态属性,并让其他视图(包括父视图)听取自动"更改"他们关心的事件。我还使用了一个全球性的" vent"类似总线的对象(只是一个扩展Backbone.Events的基本javascript对象),用于触发和侦听应用程序中的事件,有时我会在Views自身上触发事件,让父对象知道发生了什么。无论什么有效,同时尽可能保持您的建筑的无条件。

4)我真的不想在各处聆听听众。

嗯,我想骨干的一个好处就是你不必,但是要意识到观察者模式(即事件和听众)和松耦合是骨干的核心所在。 MVC(注意每个Backbone类都扩展了Events?),大多数人都会相应地使用它。

<强>参考吗

我强烈推荐PeepCode tutorials,除非您觉得自己已处于相当高级别的水平。 12块钱,但你需要从第一个或第二个开始。第三个赢得非常有用。

另外,here's a nice overview

结束