【问题标题】:remove orphaned child views in backbone删除主干中的孤立子视图
【发布时间】:2014-09-08 15:49:58
【问题描述】:

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

在这个视图中,我有一个按钮,当单击它时,它会执行一个名为“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;
    },

【问题讨论】:

  • 需要查看其余的视图定义才能提供帮助。
  • 您应该始终对要删除的视图调用 remove,并且应该覆盖 remove 以提供任何特定于视图的清理(例如 @ 987654325@电话)。

标签: backbone.js backbone-views


【解决方案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);

在添加之前注意empty的使用,如果你不想添加很多研究视图,一次只添加一个。如果您确实想要很多视图,则可以将其删除,并将内部引用保留为数组。

【讨论】:

    【解决方案2】:

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

    @CharlieBrown 的回答会奏效。但是,如果您计划创建其他视图和/或子视图,可以通过以下一种方式进行更大规模的设置:

    1) 创建一个基础视图,所有其他视图都将从该基础视图中扩展。

    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()”方法,您可以使用继承自Baseviewclose 方法关闭任何潜在的僵尸:

    //inside a view
    
    onClose: function() {
        if (this.couldBeAZombieView) this.couldBeAZombieView.close();
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-20
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-08
      • 2019-07-18
      相关资源
      最近更新 更多