如何处理初始化和Backbone.js的渲染子视图? [英] How to handle initializing and rendering subviews in Backbone.js?

查看:192
本文介绍了如何处理初始化和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 calling this.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()来的子集在父母模板的元素

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:


  1. 初始化我自己的看法

  2. 渲染我自己的看法

  3. 创建和初始化所有子视图。

  4. 分配每个孩子我的视图中查看一个元素(如的InfoView 将被分配 #info

  1. Initialize my own view
  2. Render my own view
  3. Create and initialize any child views.
  4. 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:


  1. 初始化我的看法

  2. 设置绑定监听任何改变我关心的模型

  3. 渲染我的看法

儿童视图呈现也很简单,只呈现,并设置我的的内容。同样,没有以代表团或类似的东西搞乱。

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屋!

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