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()方法)来处理新卡的显示。