0

我是 Backbone.js 的新手,这个问题真的让我很难过。

一个视图是从一个集合构建的,集合结果被过滤以将每组结果放入它们自己的数组中,然后我从每个数组中创建另一个数组,这些是显示的 4 个项目。

这在第一次呈现页面时工作正常,但是当我离开此页面然后返回页面时,现在有 8 个项目,每次我重新访问页面时,这种添加 4 的模式都会继续。

    // Locatore List Wrapper
    var LocatorPageView = Backbone.View.extend({

        postshop: [],
        postbox: [],
        postboxlobby: [],
        postboxother: [],
        closestPlaces: [],

        el: '<ul id="locator-list">',

        initialize:function () {        
            this.model.bind("reset", this.render, this);        
        },

        render:function (eventName) {
           //console.log(this)

        // Loop over collecion, assigining each type into its own array
            this.model.models.map(function(item){
                var posttype = item.get('type').toLowerCase();
                switch(posttype) {
                    case 'postshop':                              
                      this.postshop.push(item);
                      break;
                    case 'postbox':
                      this.postbox.push(item);
                      break;
                    case 'postbox lobby':
                      this.postboxlobby.push(item);
                      break;                          
                    default:
                      this.postother.push(item);
                }                     
              return ;
            }, this);   

        // Create a closest Places array of objects from the first item of each type which will be the closest item
            if (this.postshop && this.postshop.length > 0) {
                this.closestPlaces.push(this.postshop[0]);                      
            }
            if (this.postbox && this.postbox.length > 0) {
                this.closestPlaces.push(this.postbox[0]);
            }
            if (this.postboxlobby && this.postboxlobby.length > 0) {
                this.closestPlaces.push(this.postboxlobby[0]);
            }
            if (this.postother && this.postother.length > 0) {
                this.closestPlaces.push(this.postother[0]);
            }

        // Loop over the Closest Places array and append items to the <ul> contianer    
            _.each(this.closestPlaces, function (wine) {
                $(this.el).append(new LocatorItemView({
                    model:wine
                }).render().el);

            }, this);
            return this;
        }

    })

    // Locator single item
    var LocatorItemView = Backbone.View.extend({

        tagName:"li",

        template:_.template($('#singleLocatorTemplate').html()),

        render:function (eventName) {
            $(this.el).html(this.template(this.model.toJSON()));
            return this;
        },

        events: {
            "click .locator-map": "loadMap"
        },

        loadMap: function(e) {

            e.preventDefault();             
            // Instantiate new map
            var setMap = new MapPageView({
                model: this.model,
                collection: this.collection
            });

            var maptype = setMap.model.toJSON().type;
            App.navigate('mappage', {trigger:true,  replace: true});

            setMap.render();
            App.previousPage = 'locator';

        }   


    });

window.App = Backbone.Router.extend({               
    $body: $('body'),
    $wrapper: $('#wrapper'),
    $header: $('#header'),
    $page: $('#pages'),


    routes: {
               '' : '',
         'locator': 'locator'
    },          

    locator:function () {
        this.$page.empty();                                             // Empty Page

        this.places = new LocatorPageCollection();                      // New Collection
        this.placeListView = new LocatorPageView({model:this.places});  // Add data models to the collection

        this.places.fetch();

        this.$page.html(this.placeListView.render().el);                // Append the renderd content to the page
        header.set({title: 'Locator'});                                 // Set the page title
        this.$body.attr('data-page', 'locator');                        // Change the body class name
        this.previousPage = '';                                         // Set previous page for back button

    }

});     
4

2 回答 2

2

您参数中的所有属性Backbone.View.extend都附加到视图的原型。特别是,这些属性:

    postshop: [],
    postbox: [],
    postboxlobby: [],
    postboxother: [],
    closestPlaces: [],

最终附加到,LocatorPageView.prototype因此每个LocatorPageView实例共享同一组数组,并且每次使用 aLocatorPageView时,都会将更多内容推送到同一组共享数组中。

如果您在 Backbone 视图中需要任何可变属性(即数组或对象),则必须在构造函数中设置它们:

initialize: function() {
    this.postshop      = [ ];
    this.postbox       = [ ];
    this.postboxlobby  = [ ];
    this.postboxother  = [ ];
    this.closestPlaces = [ ];
}

现在每个实例都有自己的一组数组。

于 2012-09-01T21:00:18.547 回答
1

这听起来像是一个经典的僵尸视图问题。基本上当你这样做时:

this.model.bind("reset", this.render, this);

在你看来,你永远不会解绑它。因此,视图对象仍然绑定到模型并且不能从内存中删除。当您创建新视图并重置时,该侦听器仍处于活动状态,这就是您看到重复视图生成的原因。每次关闭并重做视图时,您都会积累听众,这就是它以 4 的倍数增加的原因。

unbind当您关闭视图并摆脱程序绑定时,您想要做的是您的听众。

this.model.unbind("reset", this.render, this);

这应该消除讨厌的僵尸。当我找到它时,我会添加一个包含更详细信息的链接。

更新 - 添加了有用的参考资料

不久前我也遇到了这个问题。这是 Backbone 的常见问题。@Derick Bailey 有一个非常好的解决方案,效果很好并且解释得很好。我已经包含了下面的链接。看看他在他的历史中提供的一些答案。都是好书。

僵尸!跑!

骨干网、JS 和垃圾收集

于 2012-09-01T20:57:06.280 回答