0

我有一系列綁定到Backbone集合的閃存卡。一旦我收藏了,我創建了一個播放器模型的實例。骨幹 - 如何重構此代碼以防止鬼視圖?

然後用戶可以通過使用「下一步」和「上一個」按鈕的閃存卡,其餘導航。我第一次刺殺這個我認爲很簡單的事情是將閃卡片傳給這樣的球員。

不幸的是,這樣的設計導致了一個和上一個按鈕事件被每次被點擊的時間約束。因此,例如,在第一次點擊下一個按鈕之後,該事件開始不止一次發射。我讀了一些關於幽靈視圖的地方,但無法確切知道如何將下面的代碼分解成一個塊,這將幫助我防止幽靈視圖問題。

var flashCards = new Quiz.Collections.FlashCards({ 
     id: this.model.get('card_set_id') 
}); 

Quiz.player = new Quiz.Models.FlashCardPlayer({ 
     collection: flashCards 
}) 

Quiz.Models.FlashCardPlayer = Backbone.Model.extend({ 
defaults: { 
    'currentCardIndex': 0 
}, 

initialize: function(){ 
    this.collection = this.get('collection'); 
    this.showCard(); 

}, 

showCard: function(){ 
    var flashCard = this.collection.at(this.get('currentCardIndex')); 
    var cardView = new Quiz.Views.FlashCardPlayer({ 
     model: flashCard 
    }); 
}, 

currentFlashCard: function(){ 
    return this.get('currentCardIndex'); 
}, 

previousFlashCard: function(){ 
    var currentFlashCardIndex = parseInt(this.get('currentCardIndex'), 10); 
    if(currentFlashCardIndex <= 0){ 
     console.log("no less"); 
    } 
    this.set({ 
     'currentCardIndex': currentFlashCardIndex-- 
    }); 
    this.showCard(); 
}, 

nextFlashCard: function(){ 
    var currentFlashCardIndex = parseInt(this.get('currentCardIndex'), 10); 
    if(currentFlashCardIndex >= this.collection.length){ 
     console.log("no more"); 
    } 
    currentFlashCardIndex = currentFlashCardIndex + 1; 
    this.set({ 
     'currentCardIndex': currentFlashCardIndex 
    }); 
    console.log(this.get('currentCardIndex')); 
    this.showCard(); 
} 

});

Quiz.Views.FlashCardPlayer = Backbone.View.extend({ 
    el: $('#cardSet'), 
    tagName: 'div', 
    _template: _.template($('#playerTemplate').html()), 

initialize: function(){ 
    console.log("in view flashcardplayer", this); 
    this.render(); 
}, 

events: { 
    'click #previous': 'getPreviousCard', 
    'click #next': 'getNextCard' 
}, 

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

getPreviousCard: function(){ 
    this.close(); 
    Quiz.player.previousFlashCard(); 
}, 

getNextCard: function(){ 
    this.close(); 
    Quiz.player.nextFlashCard(); 
} 

});

script#playerTemplate(type="text/template") 
<div id="state"></div> 
<div id="previous">Previous</div> 
<div id="card"> 
    <h2><%= question %></h2> 
    <h3><%= answer %></h3> 
</div> 
<div id="next">Next</div> 

回答

2

你每次都創建的Quiz.Views.FlashCardPlayer一個新的實例告訴你一個新卡。所有這些情況下執行其自己的事件處理,所以每個實例綁定到同一#next#previous元素。

我認爲有幾個概念問題在這裏:

  • 你只需要一個FlashCardPlayer觀點,這應該綁定在一個/上一個元素的事件。你可能應該有一個單獨的FlashCard視圖,它顯示單卡,玩家可以輸入,輸出,下一/上按下按鈕交換這些意見。作爲一般規則,如果你有一個元素與id,你應該只被渲染,一旦綁定到它,與單個視圖實例,否則你最終你現在有同樣的問題。

  • 你試圖東西太多到FlashCardPlayer模型。通常,模型只應瞭解其數據,而不是關於用於顯示它們的視圖(部分原因是可能需要在各種視圖中顯示一個模型)。我不介意在模型上使用nextFlashCard()previousFlashCard()方法,因爲這仍然處於存儲有關集合的數據的領域,但showCard()方法確實正在移動到視圖領域,因爲它處理表示邏輯。一個更好的主意是讓你的視圖綁定到模型上的change:currentCardIndex事件並使用this.model.get('currentCardIndex'))(或新的getCurrentCard()方法)來處理新卡的顯示。