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() 방법)을 사용하는 것입니다.