删除主干中的孤立子视图

时间:2014-09-08 15:49:59

标签: backbone.js backbone-views

我有一个骨干视图,其中包含各种研究项目的项目数据。

在这个视图中,我有一个按钮,当点击它时,它会执行一个名为&to; toggleChildView'的方法。此方法将子视图插入主页面。

在子视图中,我正在监听用户点击页面上任何位置的事件,但包含研究子评论的元素除外。

问题是,如果我关闭子视图,子视图实际上仍然在某处停留,因为事件仍在触发,并且如果我打开并关闭了子视图,则会多次触发。

因此,例如,如果我打开并关闭子视图5次,在最后关闭后,该事件仍将触发5次。

但是如果关闭它就不应该开火,而且只有在打开时才开火。

我认为我的问题最好这样说:

无论如何都要摆脱孤儿"子视图并确保一次只打开一个子视图?

谢谢!

Parent View:

    toggleChildView: function (e) {
        this.$('.displayresearchdata').toggle();
        this.$('.editdata').toggle();

        //initialize the research view into our main view
        var researchView = new researchView({ parent: this });
        self.$('.research').append(researchView.render().$el);
    },

    saveresearchdata: function (e) {
        this.model.save('researchData', this.$(".researchData").html());
    },



Child render method:

 initialize: function (options) {
        this.parent = options.parent;
    },

    render: function () {

        var self = this;
        this.$el.append(this.template());

        $("body").on("click", function (event) {
            if (!$(event.target).closest('.editdata').length) {
                if (self.parent.$('.editdata').is(":visible")) {
                    self.parent.saveresearchdata();
                }
            }
        });
            return this;
    },

2 个答案:

答案 0 :(得分:1)

由于@mu太短指出,你需要明确地删除()你添加的任何视图。

如果该视图添加了一些自定义事件侦听器,您也应该删除它们。如果您使用事件监听的view.listenTo(target, "eventname", this.functionName)风格,那么当您调用view.remove()时,由于调用stopListening()方法,这些事件处理程序将自动删除。

在您的代码中,问题在于您没有保留对您要添加的子视图的引用,因此您无法在其上调用remove。保持父母对孩子的内部引用,如:

//initialize the research view into our main view
if(this._researchView) {
  this._researchView.remove();
}

this._researchView = new researchView(...)
this.$(".research").empty().append(this._researchView.render().$el);

如果您不想添加许多researchViews,请在添加之前记下empty的使用情况,一次只能添加一个。如果你确实需要很多视图,那么你可以删除它,并将内部引用保留为数组。

答案 1 :(得分:1)

处理所谓的“僵尸”视图是使用Backbone最棘手的部分之一,如果你有很多子视图,如果你没有正确管理视图,它可能会成为一个真正的问题。关于该主题的开创性帖子是this one by Derrik Bailey,但请注意,他引用的某些方法(例如bind)现已弃用,以支持listenTo

@CharlieBrown的回答将会成功。但是,如果您打算创建其他视图和/或子视图,可以通过以下方式进行更大规模的设置:

1)创建一个Baseview,从中扩展所有其他视图。

var BaseView = Backbone.View.extend({
  //typical initialize and render functions 
  //...
  //Create the close method

    close: function () {
      if (this.onClose) this.onClose(); //looks for an onClose method in your subviews
      this.undelegateEvents();
      this.$el.off();
      this.$el.children().remove();
      this.$el.empty();
      this.stopListening();
    }
});

2)现在在Backbone路由器中,您可以创建一个trackView函数,该函数将从基本视图中调用close()方法

//within router
trackView: function (next) {
    console.log('now closing ' + next.cid);
    if (this.current) this.current.close();
    this.current = next;
},

3)现在应该在trackview内调用路由器中的所有其他视图,如下所示:

//within router
someView: function () {
        console.log('loading create user page');
        this.trackView(new someView()); //use trackView from step 2
    },

4)最后,在任何子视图中,请确保添加'onClose()'方法,您可以使用从close继承的Baseview方法关闭任何潜在的僵尸:< / p>

//inside a view

onClose: function() {
    if (this.couldBeAZombieView) this.couldBeAZombieView.close();
}

现在您正在设置更复杂的网站。还有其他方法来设置它,但这是我熟悉的。