如何处理初始化和Backbone.js的渲染子视图? [英] How to handle initializing and rendering subviews in Backbone.js?
问题描述
我有三个不同的方法来初始化并渲染视图及其子视图,其中每一个都有不同的问题。我很想知道,如果有是解决所有问题的更好的方式:
I have three different ways to initialize and render a view and its subviews, and each one of them has different problems. I'm curious to know if there is a better way that solves all of the problems:
在初始化父母的初始化函数的孩子们。这样一来,不是所有卡住在渲染,以便有上呈现阻挡以下。
Initialize the children in the parent's initialize function. This way, not everything gets stuck in render so that there is less blocking on rendering.
initialize : function () {
//parent init stuff
this.child = new Child();
},
render : function () {
this.$el.html(this.template());
this.child.render().appendTo(this.$('.container-placeholder');
}
的问题是:
-
目前最大的问题是,调用render父第二次将删除所有孩子的事件绑定的。 (这是因为如何jQuery的
$。HTML()
工作的。)这可以通过调用this.child.delegateEvents()来缓解。渲染( ).appendTo(此$ EL);
代替,但第一个,也是最经常的情况下,你做更多的工作不必要的
The biggest problem is that calling render on the parent for a second time will remove all of the childs event bindings. (This is because of how jQuery's
$.html()
works.) This could be mitigated by callingthis.child.delegateEvents().render().appendTo(this.$el);
instead, but then the first, and the most often case, you're doing more work unnecessarily.
通过附加的孩子,你强制渲染功能有家长DOM结构方面的知识,让你得到你想要订购。这意味着改变一个模板可能需要更新视图的渲染功能。
By appending the children, you force the render function to have knowledge of the parents DOM structure so that you get the ordering you want. Which means changing a template might require updating a view's render function.
初始化父的初始化()
还在,但不是附加,使用 setElement()。delegateEvents()$ c中的孩子们$ c>来的子集在父母模板的元素
Initialize the children in the parent's initialize()
still, but instead of appending, use setElement().delegateEvents()
to set the child to an element in the parents template.
initialize : function () {
//parent init stuff
this.child = new Child();
},
render : function () {
this.$el.html(this.template());
this.child.setElement(this.$('.placeholder-element')).delegateEvents().render();
}
问题:
- 这使得
delegateEvents()
现在有必要,这比它仅仅是在第一个方案的后续调用需要一个轻微的负。
- This makes the
delegateEvents()
necessary now, which is a slight negative over it only being necessary on subsequent calls in the first scenario.
在初始化儿童父母的渲染()
方法来代替。
Initialize the children in the parent's render()
method instead.
initialize : function () {
//parent init stuff
},
render : function () {
this.$el.html(this.template());
this.child = new Child();
this.child.appendTo($.('.container-placeholder').render();
}
问题:
-
这意味着渲染功能现在必须同时拴住与所有的初始化逻辑。
This means that the render function now has to be tied down with all of the initialization logic as well.
如果我编辑的子视图之一的状态,然后调用渲染父,一个全新的孩子将作出所有其当前状态将会丢失。这也似乎是它可以让冒险内存泄漏。
If I edit the state of one of the child views, and then call render on the parent, a completely new child will be made and all of its current state will be lost. Which also seems like it could get dicey for memory leaks.
真的很好奇,让你的球员这个服食。你会用哪种方案?或者是有第四个神奇的一个解决所有这些问题?
Really curious to get your guys' take on this. Which scenario would you use? or is there a fourth magical one that solves all of these problems?
你有没有保持跟踪渲染状态的一个视图?说 renderedBefore
标志?似乎真的janky。
Have you ever kept track of a rendered state for a View? Say a renderedBefore
flag? Seems really janky.
推荐答案
这是一个很大的问题。主干是伟大的,因为缺乏假设它使,但它确实意味着你必须(决定如何)实现这样的自己的东西。通过我自己的东西看后,我发现我(种)的使用情景1和方案2的组合,我不认为一个神奇的第四次方案存在的原因,根本不够的,你的一切场景中的1安培做的; 2必须做到的。
This is a great question. Backbone is great because of the lack of assumptions it makes, but it does mean you have to (decide how to) implement things like this yourself. After looking through my own stuff, I find that I (kind of) use a mix of scenario 1 and scenario 2. I don't think a 4th magical scenario exists because, simply enough, everything you do in scenario 1 & 2 must be done.
我觉得这是最简单的解释我是怎么样用一个例子来处理它。说我有这个简单的页面分为指定的观点:
I think it'd be easiest to explain how I like to handle it with an example. Say I have this simple page broken into the specified views:
说出HTML是,被渲染后,像这样:
Say the HTML is, after being rendered, something like this:
<div id="parent">
<div id="name">Person: Kevin Peel</div>
<div id="info">
First name: <span class="first_name">Kevin</span><br />
Last name: <span class="last_name">Peel</span><br />
</div>
<div>Phone Numbers:</div>
<div id="phone_numbers">
<div>#1: 123-456-7890</div>
<div>#2: 456-789-0123</div>
</div>
</div>
希望这是pretty明显HTML如何与图表相匹配。
Hopefully it's pretty obvious how the HTML matches up with the diagram.
的 ParentView
持有2子视图,的InfoView
和 PhoneListView
以及一些额外的div,其中一, #NAME
,需要在某点被设置。 PhoneListView
拥有自己的子视图,数组 PhoneView
项。
The ParentView
holds 2 child views, InfoView
and PhoneListView
as well as a few extra divs, one of which, #name
, needs to be set at some point. PhoneListView
holds child views of its own, an array of PhoneView
entries.
因此,在您的实际问题。我处理的初始化和渲染基于不同的视图类型。我打破了我的观点分为两类,父
的意见和儿童
的看法。
So on to your actual question. I handle initialization and rendering differently based on the view type. I break my views into two types, Parent
views and Child
views.
它们之间的区别很简单,父
的意见持孩子的意见,而儿童
的意见没有。所以在我的例子中, ParentView
和 PhoneListView
是父
的意见,而的InfoView
和 PhoneView
项儿童
的意见。
The difference between them is simple, Parent
views hold child views while Child
views do not. So in my example, ParentView
and PhoneListView
are Parent
views, while InfoView
and the PhoneView
entries are Child
views.
就像我前面提到的,这两类之间最大的区别是他们允许渲染时。在一个完美的世界,我想父
意见,只会渲染一次。这是由他们的孩子的意见,以处理任何重新渲染当模型(S)的变化。 儿童
的意见,在另一方面,我允许重新渲染随时因为他们没有任何其他的看法依赖于他们所需要的。
Like I mentioned before, the biggest difference between these two categories is when they're allowed to render. In a perfect world, I want Parent
views to only ever render once. It is up to their child views to handle any re-rendering when the model(s) change. Child
views, on the other hand, I allow to re-render anytime they need since they don't have any other views relying upon them.
在更详细一点,为父
的意见我喜欢我的初始化
的功能做了几件事情:
In a little more detail, for Parent
views I like my initialize
functions to do a few things:
- 初始化我自己的看法
- 渲染我自己的看法
- 创建和初始化所有子视图。
- 分配每个孩子我的视图中查看一个元素(如
的InfoView
将被分配#info
)
- Initialize my own view
- Render my own view
- Create and initialize any child views.
- Assign each child view an element within my view (e.g. the
InfoView
would be assigned#info
).
步骤1 pretty自我解释。
Step 1 is pretty self explanatory.
步骤2,渲染,是这样做之前,我尝试将它们分配子视图依赖于已有的任何元素存在。通过这样做,我知道所有的孩子事件
将被正确设置,我可以重新渲染他们的块,因为我想尽可能多的时间,而不必担心重新委派什么。我实际上并不渲染
这里任何一个孩子的意见,我让他们做自己的初始化中
。
Step 2, the rendering, is done so that any elements the child views rely on already exist before I try to assign them. By doing this, I know all child events
will be correctly set, and I can re-render their blocks as many times as I want without worrying about having to re-delegate anything. I do not actually render
any child views here, I allow them to do that within their own initialization
.
步骤3和4是在为我传递的同时报
中在创建子视图实际处理。我想传递一个元素在这里,因为我觉得父母应该确定在其自己的看法孩子被允许把它的内容。
Steps 3 and 4 are actually handled at the same time as I pass el
in while creating the child view. I like to pass an element in here as I feel the parent should determine where in its own view the child is allowed to put its content.
有关渲染,我尽量保持pretty简单的父
的意见。我想在渲染
函数做无非呈现父视图。没有事件委派,没有子视图渲染,什么都没有。只是一个简单的渲染。
For rendering, I try to keep it pretty simple for Parent
views. I want the render
function to do nothing more than render the parent view. No event delegation, no rendering of child views, nothing. Just a simple render.
有时这并不总是工作,虽然。比如上面我举的例子中,#NAME
元素将需要的任何时间模型的变化内更新的名称。然而,此块是 ParentView
模板的一部分,而不是由专门的儿童
视图处理,所以我解决了。我会建立某种形式的 subRender
函数的仅的替换内容的#NAME
元素,没有垃圾的整个 #parent
元素。这似乎是一个黑客,但我真的发现它比不必担心重新渲染了整个DOM和重新连接的元素和这样更好。如果我真的想让它干净,我想创建一个新的儿童
视图(类似于的InfoView
)的将处理#NAME
块。
Sometimes this doesn't always work though. For instance in my example above, the #name
element will need to be updated any time the name within the model changes. However, this block is part of the ParentView
template and not handled by a dedicated Child
view, so I work around that. I will create some sort of subRender
function that only replaces the content of the #name
element, and not have to trash the whole #parent
element. This may seem like a hack, but I've really found it works better than having to worry about re-rendering the whole DOM and reattaching elements and such. If I really wanted to make it clean, I'd create a new Child
view (similar to the InfoView
) that would handle the #name
block.
现在的儿童
的意见,初始化
类似于 pretty父
的意见,只是没有创造任何进一步的儿童
意见。所以:
Now for Child
views, the initialization
is pretty similar to Parent
views, just without the creation of any further Child
views. So:
- 初始化我的看法
- 设置绑定监听任何改变我关心的模型
- 渲染我的看法
儿童
视图呈现也很简单,只呈现,并设置我的报
的内容。同样,没有以代表团或类似的东西搞乱。
Child
view rendering is also very simple, just render and set the content of my el
. Again, no messing with delegation or anything like that.
下面是一些例子code就是我 ParentView
可能看起来像:
Here is some example code of what my ParentView
may look like:
var ParentView = Backbone.View.extend({
el: "#parent",
initialize: function() {
// Step 1, (init) I want to know anytime the name changes
this.model.bind("change:first_name", this.subRender, this);
this.model.bind("change:last_name", this.subRender, this);
// Step 2, render my own view
this.render();
// Step 3/4, create the children and assign elements
this.infoView = new InfoView({el: "#info", model: this.model});
this.phoneListView = new PhoneListView({el: "#phone_numbers", model: this.model});
},
render: function() {
// Render my template
this.$el.html(this.template());
// Render the name
this.subRender();
},
subRender: function() {
// Set our name block and only our name block
$("#name").html("Person: " + this.model.first_name + " " + this.model.last_name);
}
});
您可以看到我的执行 subRender
在这里。通过具有必然 subRender
的变化,而不是渲染
,我不担心爆破,距离重建整个块。
You can see my implementation of subRender
here. By having changes bound to subRender
instead of render
, I don't have to worry about blasting away and rebuilding the whole block.
下面的例子code为的InfoView
块:
Here's example code for the InfoView
block:
var InfoView = Backbone.View.extend({
initialize: function() {
// I want to re-render on changes
this.model.bind("change", this.render, this);
// Render
this.render();
},
render: function() {
// Just render my template
this.$el.html(this.template());
}
});
的绑定是这里的重要组成部分。通过结合我的模型,我从来没有担心手工调用渲染
自己。如果模型的变化,此块将重新渲染本身,而不会影响任何其他意见。
The binds are the important part here. By binding to my model, I never have to worry about manually calling render
myself. If the model changes, this block will re-render itself without affecting any other views.
的 PhoneListView
将类似于 ParentView
,你只需要多一点逻辑都你初始化
和渲染
函数来处理集合。你如何处理收集真的取决于你,但你至少需要被倾听收集事件,并决定要如何渲染(追加/删除,或者只是重新渲染了整个块)。我个人喜欢追加新的观点和删除旧的,而不是重新渲染整个视图。
The PhoneListView
will be similar to the ParentView
, you'll just need a little more logic in both your initialization
and render
functions to handle collections. How you handle the collection is really up to you, but you'll at least need to be listening to the collection events and deciding how you want to render (append/remove, or just re-render the whole block). I personally like to append new views and remove old ones, not re-render the whole view.
的 PhoneView
将几乎等同于的InfoView
,只听模式改变它关心。
The PhoneView
will be almost identical to the InfoView
, only listening to the model changes it cares about.
希望这有助于一点,请让我知道如果有什么是混乱还是不够详细。
Hopefully this has helped a little, please let me know if anything is confusing or not detailed enough.
这篇关于如何处理初始化和Backbone.js的渲染子视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!