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

Jac*_*ack 21 backbone.js

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

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

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

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

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

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

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

Ben*_*rts 44

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

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

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

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

在骨干应用程序中,有许多有用的方法可以使用视图.我通常在我的应用中看到一些重叠的视图类型:

我通常有一个或多个"根级"视图.根级视图通常是初始化,呈现和保持对处理页面特定部分的子视图的引用的地方.所述el根级视图的往往是"体"或身体内的另一高电平元件.在某些情况下,根级视图有自己的HTML来观察和/或渲染.在其他情况下,根级视图可能根本没有el,只管理子视图.我在全局"app"命名空间对象中保留对每个根级视图(通常只有一个)的引用.

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

除了"根级/父/子"范例之外,我倾向于看到视图符合以下两个类别之一:(1)静态:意味着一旦视图被初始化,视图及其el周围,​​即使是东西里面的变化; (2)基于各种事件来来去去的动态.通常,我的根级视图始终是静态的.它们通常也对应于现有的DOM元素,例如"body"或"#my-div".子视图通常是动态的,但也可能是静态的.(提示:用于在声明静态视图时el: '#element-id'使用现有DOM元素el.动态视图通常不指定现有el;它们使用tagName idclassName描述动态视图将生成的元素.)

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

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

现在在这种背景下,问题

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

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

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

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

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

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

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

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

4)我真的不想在各地开始投掷听众.

好吧,我想骨干的一个好处就是你不必,但是意识到Observer模式(即事件和监听器)和松散耦合是MVC主干风格的核心(注意每个Backbone类都扩展了Events) ?),大多数人都会相应地使用它.

参考文献?

我强烈推荐PeepCode教程,除非你觉得你已经处于非常高级的水平.12块钱,但你需要从第一个开始,或者第二个和第三个开始不是很有用.

此外,这是一个很好的概述.

结束