Backbone.js - 嵌套视图是否应该维护彼此的引用? [英] Backbone.js - Should nested Views maintain references to each other?

查看:14
本文介绍了Backbone.js - 嵌套视图是否应该维护彼此的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

If a Backbone View creates new Views inside its render() method, should these Views be maintained as data members? A typical render method looks like:

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

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

This kind of chaining of render methods means that the nested View is really only created so that it too can chain any render methods and return a nicely constructed element. The View is left for garbage collection I assume?

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

If the nested View is to be modified... perhaps heavily, should it just be (re)created, or should it be modified through the data-member reference?

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

The problem I'm having is the nested Views receive events that require them to modify their own nested Views, and sometime their parent View.

我真的不希望 top 开始到处乱扔听众.传递对父视图的引用并从子视图调用 render() 会导致内存泄漏,因为父视图创建了一个新的子视图,而原始子视图维护对其父视图的引用!

I don't really want top start throwing listeners around everywhere. And passing in references to parent Views and called render() from the child View results in a memory leak since the parent creates a new child View while the original child View maintains a reference to its parent!

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

It's just not very framework-like at the moment. Does anyone have any resources that would help me solve this problem in a frame-work like manner?

推荐答案

(警告:我的回答变成了 tl;dr 论文)

(warning: my answer became a tl;dr treatise)

我很早就有一些相同的问题,为了构建一些非常复杂的应用程序,我做了功课,所以我将提供我的观点.

I had some of these same questions early on, and have done my homework in order to build a few pretty complex apps, so I'll offer my perspective.

学习骨干的最大挑战是它是如此的没有主见,并且可以(并且正在)以多种不同的方式使用,以至于很难弄清楚如何做正确"的事情,或者至少以一种好的方式做开始了.使用主干的方法不止一种,而且它的灵活性使它成为几乎所有应用程序的绝佳结构,希望我能帮助提供一些指导.(我可能可以在此处的每个句子中附加IMO").

The big challenge with learning backbone is that it is so unopinionated and can be (and is) used in so many different ways that it's hard to figure out how to do something "right" or at least in a good way when you're starting out. There isn't just one true way to use backbone, but its flexibility makes it an awesome structure for almost any app, and hopefully I can help provide some guidance. (I could probably attach "IMO" to every sentence in here).

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

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

In backbone apps, there are a lot of useful ways to use views. I generally see a few overlapping types of views in my apps:

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

I typically have one or more "root-level" views. Root-level views are often a place to initialize, render, and keep references to child views that handle specific parts of the page. The el of a root-level view is often "body" or another high level element within the body. In some cases, a root-level view has its own HTML to observe and/or render. In others, a root-level view may have no el at all and just manages child views. I keep a reference to each root-level view (there is often only one) in a global 'app' namespace object.

除了根级"视图之外,通常还有子视图".子视图由父"视图初始化和呈现,父视图可以是根级视图或另一个子视图.父视图负责根据应用程序的需要初始化、渲染、隐藏、显示和/或销毁其子视图.有时,父视图可能会跟踪子视图的可变数量的实例(例如,一个 PlaylistView 有 N 个 SongView).通常,父母会保留对孩子的引用,但有时这是不必要的(更多内容见下文).

In addition to "root-level" views, there are typically "child views". A child view is initialized and rendered by a "parent" view, which may be a root-level view or another child view. Parent views are in charge of initializing, rendering, hiding, showing, and/or destroying their children as the app requires. Sometimes a parent view may keep track of a variable number of instances of a child View (e.g., a PlaylistView has N SongViews). Often, parents maintain references to children, but sometimes it is unnecessary (more on this below).

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

In addition to the 'root-level/parent/child' paradigm, I tend to see views fit into one of two categories: (1) static: meaning that once the view is initialized, the view and its el stick around, even if stuff changes inside it; and (2) dynamic, which come and go, based on various events. Typically, my root-level views are always static. They also typically correspond to an existing DOM element, e.g., 'body' or '#my-div'. Child views are often dynamic, but may be static as well. (Tips: use el: '#element-id' to use an existing DOM element as el when declaring a static View. Dynamic views typically don't specify an existing el; they use tagName id and className to describe the element that the dynamic view will generate.)

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

Views essentially have 3 functions: (1) render themselves and their children when told to do so by their parents or in response to events (or in the case of a root-level view, when initialized by a router or a 'main' function, etc.), (2) respond to UI events from DOM elements within their el (but not within the el of any child view) by updating models or collections or triggering custom Backbone events, and (3) observe and respond to Backbone (model, collection, etc.) events that require something to be rendered or changed within their el (but not within the el of any child view.) One sometimes-useful trick is that child views can trigger events on themselves (this.trigger('customEvent')) that parent views can observe ( childView.on('customEvent', this.handler, this) ).

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

For additional interesting perspectives on backbone view patterns see: this and this.

现在在这种情况下,开始提问

Now in that context, on to questions

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

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

If you instantiate a child view as a local var in a parent's render (or other) method and render it, and then the function goes out of scope, I can understand your fear of garbage collection or that the view won't be able to do what it needs to do. No need to fear the garbage collector, just the zombies. If your view has any event handlers whatsoever, whether UI Event handlers declared in the "events" declaration, or bindings to other Backbone objects' events, or other DOM-based event listeners, your view will not be garbage collected even though you don't have a reference to it anymore--it will still exist in memory and respond to the events. On the other hand, if a view doesn't have any event handlers, then its only job is to render an element, so who cares if the javascript object that rendered it sticks around--it will probably be garbage collected because it should be. See this, for a great understanding of js garbage collection in general and how it relates to Backbone.js.

更大的问题是 僵尸视图.如果要从 DOM 中删除视图并在您的应用程序中的某个时候基本上将其丢弃,那么请确保它们要么完全删除自己,要么父视图应保留对它们的引用并删除它们.并且不要重新创建和替换已经创建但没有正确删除的视图.移除是通过在视图上调用 .remove() 来完成的,再加上使用 off(...) 取消绑定您之前使用 on(...) 绑定的任何外部 Backbone 事件代码>.Backbone 的最新版本 (1.0+) 通过添加 "listenTo" 和 "stopListening" 方法使这个问题更容易解决 到视图原型.如果您要动态地将视图添加到 DOM 或从 DOM 中添加视图,请理解并使用这些方法而不是打开/关闭.提示:设置一个像这样的hacky jqueryremove"事件可以轻松地启用视图自动删除和当他们的 el 从 DOM 中删除时进行自我清理(如果您的应用流程中没有可以达到相同目的的事件).

The bigger concern is of Zombie views. If views are to be removed from the DOM and essentially discarded at some point in your app, then make sure they either fully remove themselves or that parent views should keep a reference to them and remove them. And don't re-create and replace views that have already been created and not properly removed. Removal is accomplished by calling .remove() on the view, plus unbinding any external Backbone events that you were previously bound using on(...) using off(...). Recent versions (1.0+) of Backbone make this issue more easily addressed by adding the "listenTo" and "stopListening" methods to the View prototype. Understand and use these methods instead of on/off if you're dynamically adding the views to and from the DOM. Tip: Setting up a a hacky jquery "remove" event like this one can easily enable views to autonomously remove and clean-up themselves when their el is removed from the DOM (in the event that there isn't an event in your app flow that can serve the same purpose).

2) 子视图是否应该作为父视图的数据成员进行维护?

这取决于.我不认为父视图为了有限的目的而知道他们的子视图违反了 MVC 的任何黄金原则.有时,如果/在需要时,具有对特定子视图实例的成员引用的父级是管理子视图的好方法.正如我所指出的,有时父视图会响应需要它们渲染、重新渲染、隐藏或删除其子视图的事件.有时,他们可能想收听子视图触发的事件.然而,父母不应该过多地参与他们子视图的 el 内部的任何事情.

It depends. I don't think parent views being aware of their child views for limited purposes violates any golden principles of MVC. Sometimes, a parent having member references to specific child view instances is a great way to manage child views if/when you need it. As I indicated, sometimes parent views respond to events that require them to render, re-render, hide, or remove their child views. Sometimes they may want to listen to events that child views trigger on themselves. Parents, however, shouldn't get too involved in anything inside of their child views' el's though.

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

That said, don't overuse these types of references. Many times, you will not need to use references to child views, because the children can take care of themselves. As I mentioned, views, once rendered, should only A) watch for UI events inside their el (but typically not inside any child view's el) and update models or collections or trigger events in response to these UI events, or B) watch for events from other backbone objects (typically models or collections or other views) and take actions (e.g., update their own UI elements) in response. In many instances, a view can take care of itself and even remove itself. If another View or other Backbone object cares about a UI event happening in your view, update a model or trigger an event on the view and let them observe it. Likewise, if something outside your view requires updated rendering in your view, listen for a change to a model or wait on a corresponding custom event. As a general principle, views should be blissfully unaware of each other, with the exception of parents minding their children when it makes sense.

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

没有.绝不.我想不出一个场景,您需要通过对父级的引用来完成某些事情,而这无法通过更改父级正在观察的模型或触发事件(例如,自定义事件说嘿,X 发生了")在子视图本身或另一个基于事件"的主干对象上.在 Backbone 中,我使用模型来表示我的数据和我的状态.因此,如果某个视图中发生的事情改变了我的应用程序的状态,那么我会更改模型的相应状态属性,并让其他视图(包括父视图)监听自动更改"事件(如果他们关心的话).我还使用一个全局的通风口"类总线对象(只是一个扩展 Backbone.Events 的基本 javascript 对象)来触发和侦听应用程序中的事件,有时我会在视图本身上触发事件,让父对象知道发生了一些事情.任何可行的方法,同时尽可能保持您的架构清晰.

No. Never. I can't think of a single scenario where you would need to accomplish something through a reference to a parent that couldn't be accomplished by either changing a model that the parent is observing, or triggering an event (e.g., a custom event saying "hey, X happened") on the child view itself or on another backbone "Events"-based object. In Backbone, I use models to represent both my data AND my state. So if something happens in a view that changes the state of my application, I then change the corresponding state attribute of a model and let other views (including the parent) listen to the automatic "change" event if they care. I also use a global "vent" bus-like object (just a basic javascript object that extends Backbone.Events) for triggering and listening on events across the app, and sometimes I trigger events on Views themselves to let parent objects know that something happened. Whatever works, while keeping your architecture as untangled as possible.

4) 我真的不希望 top 开始到处乱扔听众.

好吧,我想关于主干的一个好处是您不必这样做,但要意识到观察者模式(即事件和侦听器)和松散耦合是主干 MVC 风格的核心(请注意,每个Backbone 类扩展了事件?),并且大多数人相应地使用它.

Well I guess one good thing about backbone is that you don't have to, but realize that the Observer pattern (ie events & listeners) and loose coupling are at the heart of backbone's flavor of MVC (notice that every single Backbone class extends Events?), and most people use it accordingly.

参考资料?

我强烈推荐PeepCode 教程,除非您觉得自己已经处于相当高的水平等级.12块钱一块,但你需要从第一个或第二个开始第三个不会很有用.

I strongly recommend the PeepCode tutorials unless you feel you're already at a pretty advanced level. 12 bucks a piece, but you need to start with the first one or the second & third won't be very useful.

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

结束

这篇关于Backbone.js - 嵌套视图是否应该维护彼此的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆