本文介绍了如何在 Backbone.js 中渲染和附加子视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个嵌套视图设置,它可以深入我的应用程序.我能想到的初始化、渲染和附加子视图的方法有很多,但我想知道常见的做法是什么.

I have a nested-View setup which can get somewhat deep in my application. There are a bunch of ways I could think of initializing, rendering and appending the sub-views, but I'm wondering what common practice is.

以下是我想到的几个:

initialize : function () {

    this.subView1 = new Subview({options});
    this.subView2 = new Subview({options});
},

render : function () {

    this.$el.html(this.template());

    this.subView1.setElement('.some-el').render();
    this.subView2.setElement('.some-el').render();
}

优点:您不必担心通过附加来维护正确的 DOM 顺序.视图很早就被初始化了,所以在渲染函数中没有那么多事情要一次性完成.

Pros: You don't have to worry about maintaining the right DOM order with appending. The views are initialized early on, so there isn't as much to do all at once in the render function.

缺点:您被迫重新委托Events(),这可能代价高昂?父视图的渲染函数被所有需要发生的子视图渲染弄得一团糟?您无法设置元素的 tagName,因此模板需要维护正确的 tagNames.

Cons: You are forced to re-delegateEvents(), which might be costly? The parent view's render function is cluttered with all of the subview rendering that needs to happen? You don't have the ability to set the tagName of the elements, so the template needs to maintain the correct tagNames.

另一种方式:

initialize : function () {

},

render : function () {

    this.$el.empty();

    this.subView1 = new Subview({options});
    this.subView2 = new Subview({options});

    this.$el.append(this.subView1.render().el, this.subView2.render().el);
}

优点:您不必重新委派事件.您不需要只包含空占位符的模板,并且您的 tagName 将重新由视图定义.

Pros: You don't have to re-delegate events. You don't need a template that just contains empty placeholders and your tagName's are back to being defined by the view.

缺点:您现在必须确保以正确的顺序附加内容.父视图的渲染仍然被子视图渲染杂乱无章.

Cons: You now have to make sure to append things in the right order. The parent view's render is still cluttered by the subview rendering.

使用 onRender 事件:

initialize : function () {
    this.on('render', this.onRender);
    this.subView1 = new Subview({options});
    this.subView2 = new Subview({options});
},

render : function () {

    this.$el.html(this.template);

    //other stuff

    return this.trigger('render');
},

onRender : function () {

    this.subView1.setElement('.some-el').render();
    this.subView2.setElement('.some-el').render();
}

优点:子视图逻辑现在与视图的 render() 方法分离.

Pros: The subview logic is now separated from the view's render() method.

使用 onRender 事件:

initialize : function () {
    this.on('render', this.onRender);
},

render : function () {

    this.$el.html(this.template);

    //other stuff

    return this.trigger('render');
},

onRender : function () {
    this.subView1 = new Subview();
    this.subView2 = new Subview();
    this.subView1.setElement('.some-el').render();
    this.subView2.setElement('.some-el').render();
}

我在所有这些示例中混合并匹配了一堆不同的实践(对此感到抱歉),但是您会保留或添加哪些实践?你不会做什么?

I've kind of mix and matched a bunch of different practices across all of these examples (so sorry about that) but what are the ones that you would keep or add? and what would you not do?

实践总结:

  • initializerender 中实例化子视图?
  • renderonRender中执行所有子视图渲染逻辑?
  • 使用 setElement 还是 append/appendTo?
  • Instantiate subviews in initialize or in render?
  • Perform all sub-view rendering logic in render or in onRender?
  • Use setElement or append/appendTo?

推荐答案

我通常看到/使用过几个不同的解决方案:

I have generally seen/used a couple of different solutions:

解决方案 1

var OuterView = Backbone.View.extend({
    initialize: function() {
        this.inner = new InnerView();
    },

    render: function() {
        this.$el.html(template); // or this.$el.empty() if you have no template
        this.$el.append(this.inner.$el);
        this.inner.render();
    }
});

var InnerView = Backbone.View.extend({
    render: function() {
        this.$el.html(template);
        this.delegateEvents();
    }
});

这与您的第一个示例类似,但有一些更改:

This is similar to your first example, with a few changes:

  1. 附加子元素的顺序很重要
  2. 外部视图不包含要在内部视图上设置的 html 元素(意味着您仍然可以在内部视图中指定 tagName)
  3. render() 在内部视图的元素被放入 DOM 之后被调用,如果你的内部视图的 render() 方法正在放置/调整自身大小,这会很有帮助在页面上基于其他元素的位置/大小(根据我的经验,这是一个常见用例)
  1. The order in which you append the sub elements matters
  2. The outer view does not contain the html elements to be set on the inner view(s) (meaning you can still specify tagName in the inner view)
  3. render() is called AFTER the inner view's element has been placed into the DOM, which is helpful if your inner view's render() method is placing/sizing itself on the page based on other elements' position/size (which is a common use case, in my experience)

解决方案 2

var OuterView = Backbone.View.extend({
    initialize: function() {
        this.render();
    },

    render: function() {
        this.$el.html(template); // or this.$el.empty() if you have no template
        this.inner = new InnerView();
        this.$el.append(this.inner.$el);
    }
});

var InnerView = Backbone.View.extend({
    initialize: function() {
        this.render();
    },

    render: function() {
        this.$el.html(template);
    }
});

解决方案 2 可能看起来更简洁,但根据我的经验,它引起了一些奇怪的事情,并对性能产生了负面影响.

Solution 2 may look cleaner, but it has caused some strange things in my experience and has affected performance negatively.

我通常使用解决方案 1,原因如下:

I generally use Solution 1, for a couple of reasons:

  1. 我的很多视图都依赖于在它们的 render() 方法中已经存在于 DOM 中
  2. 当外部视图被重新渲染时,视图不必重新初始化,重新初始化会导致内存泄漏,也会导致现有绑定出现奇怪的问题
  1. A lot of my views rely on already being in the DOM in their render() method
  2. When the outer view is re-rendered, views don't have to be re-initialized, which re-initialization can cause memory leaks and also cause freaky issues with existing bindings

请记住,如果每次调用 render() 时都初始化 new View(),则该初始化将调用 delegateEvents() 无论如何.因此,正如您所表达的那样,这不一定是骗局".

Keep in mind that if you are initializing a new View() every time render() is called, that initialization is going to call delegateEvents() anyway. So that shouldn't necessarily be a "con", as you've expressed.

这篇关于如何在 Backbone.js 中渲染和附加子视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 23:12