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インスタンスは同じ配列のLocatorPageViewセットを共有し、 を使用するたびに、同じ共有配列のセットにさらに多くのものをプッシュします。

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 に答える