简体   繁体   English

如何在Backbone.js中呈现嵌套视图?

[英]How to render nested views in Backbone.js?

I have a tree of categories and I would like to do rending using by Backbone.js instead of using jQuery or do rendering on the server-side. 我有一个类别树,我想使用Backbone.js而不是使用jQuery或在服务器端进行渲染。 I have the following breakout that I described as template: 我有以下突破,我描述为模板:

<li>
    <select class="categories">
        <option value="">Select</option>
    </select>
    <input class="edit" type="button" value="Edit">
    <input class="add" type="button" value="Add">
</li>

The tag select I render separately as inner view. 标签select我作为内部视图单独渲染。 When I change select I need get nested categories from the server and append them to the tag li using the template above wrapped in the tag ul . 当我更改select时,我需要从服务器获取嵌套类别,并使用包含在标记ul中的上述模板将它们附加到标记li In outer view I create inner view and listen events on click at editing and adding. 在外部视图中,我创建内部视图并在编辑和添加时单击时监听事件。 I have a trouble with the last events when the level of nesting is more than one because they are fires equal times to the level of nesting. 当嵌套级别超过一级时,我遇到了最后事件的问题,因为它们的触发次数与嵌套级别相同。 What am I doing wrong? 我究竟做错了什么?

The below code snippet shows how I work with outer and inner views: 下面的代码片段显示了我如何使用外部和内部视图:

    var CategoriesInnerView = Backbone.View.extend({
        tagName:       'select',
        initialize:    function(){
            _.bindAll(this,'addOne','addAll');
            this.collection.bind('reset',this.addAll);
        },
        addOne:        function(category){
            this.$el.append(new CategoryView({model:category}).render().el);
        },
        addAll:        function(){
            this.collection.each(this.addOne);
        },
        events:        {
            'change':'changeSelected'
        },
        changeSelected:function(){
            var children = new Categories();
            children.url = 'categories/' + this.$el.val();

            var childrenView = new CategoriesOuterView({collection:children});
            this.$el.parent().find('ul').remove();
            this.$el.parent().append(childrenView.render().el);

            children.fetch();
        }
    });

    var CategoriesOuterView = Backbone.View.extend({
        tagName:   'ul',
        template:  _.template($('#categories-template').html()),
        initialize:function(){
            this.inner = new CategoriesInnerView({collection:this.collection});
        },
        render:    function(){
            this.$el.html(this.template);

            this.inner.setElement(this.$('select')).render();

            return this;
        },
        events:    {
            'click .edit':'edit',
            'click .add': 'add'
        },
        edit:    function(){
            this.renderForm(this.collection.get(this.inner.$el.val()));
        },
        add:    function(){
            this.renderForm(new Category());
        },
        renderForm:function(category){
            // some code to render the form
        }
    });

When you set up nested views, you have to take into account the fact that events will bubble up the DOM tree and that Backbone handles DOM events at the view.el level. 设置嵌套视图时,必须考虑事件将冒出DOM树并且Backbone在view.el级别处理DOM事件的事实。 This means that in your scenario, nested nodes will also trigger events in the parent nodes if you let the event go up the hierarchy. 这意味着在您的方案中,如果让事件在层次结构中上升,嵌套节点也将在父节点中触发事件。

See http://jsfiddle.net/PX2PL/ for a demo 有关演示,请参见http://jsfiddle.net/PX2PL/

A simple solution would be to stop the event propagation in your callbacks 一个简单的解决方案是在回调中停止事件传播

var CategoriesOuterView = Backbone.View.extend({
    events:    {
        'click .edit':'edit',
        'click .add': 'add'
    },
    edit: function(e) {
        e.stopPropagation();
        this.renderForm(this.collection.get(this.inner.$el.val()));
    },
    add: function(e) {
        e.stopPropagation();
        this.renderForm(new Category());
    }
}

And an updated demo http://jsfiddle.net/PX2PL/1/ 和更新的演示http://jsfiddle.net/PX2PL/1/

We really need to seem some of your code to answer this properly, but it sounds like one of two things is happening: 我们真的需要看一些你的代码才能正确回答这个问题,但这听起来像是发生了两件事之一:

1) you are instantiating your view on the same element multiple times 1)您多次在同一元素上实例化您的视图

2) your event selectors are too broad 2)你的事件选择器太宽泛了

But without actually seeing (the relevant parts of) your view, it's hard to say more than that. 但是,如果没有真正看到(相关部分)您的观点,那么很难说更多。


Tangentially-Related Side Note 切线相关侧注

BTW, when you have something like this, there are two basic approaches you can take: 顺便说一句,当你有这样的东西时,你可以采取两种基本方法:

1) you can have your parent view create sub views, and put the event handling on the sub-views 1)您可以让父视图创建子视图,并将事件处理放在子视图上

2) you can have your parent view create sub views, or not (it could create all the HTML itself), and put the event handling on it. 2)您可以让父视图创建子视图,或者不创建子视图(它可以创建所有HTML本身),并将事件处理放在其上。

The advantage of #1 is simplicity: your event handlers can just refer to this to refer to the relevant view. #1的优点是简单:您的事件处理程序可以引用this来引用相关视图。 However, there's a problem with #1 if you have to scale it up too much: millions of views, each with their own event handlers, will hurt performance. 但是,如果你需要扩展太多,那么#1会出现问题:数百万个视图,每个视图都有自己的事件处理程序,会损害性能。

So, if performance is/will be important, #2 is better because you're only doing a single set of event hookups. 因此,如果性能是/将是重要的,#2更好,因为你只做一组事件连接。 However, you're event handlers will have to be smarter, because they'll have to figure out what element their working on based on the provided event (ie. e.target , vs. this in the #1 approach). 但是,你的事件处理程序必须是聪明的,因为他们必须要弄清楚什么元素及其工作基础上所提供的事件(即e.target ,对this在#1的方法)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM