2013-04-05 149 views
0

我是新來的骨幹,我有一個對象集合和一個視圖,將它們顯示爲一個列表。它的設置是每當一個對象被添加到集合中時,視圖都被重新渲染。這實際上效率很低,因爲如果我一次將20件東西添加到集合中,那麼在最後添加項目後只需渲染一次就會渲染20次。在完成向集合中添加事物之前,我如何讓渲染骨幹繼續渲染?讓骨幹等待渲染視圖

這裏是我的代碼:

<html> 
    <head> 
     <meta charset="utf-8" /> 
     <title>Looking At Underscore.js Templates</title> 
    </head> 
    <body> 
     <script type="text/template" class="template"> 
      <ul id="petlist"> 
       <% _.each(model.pets, function(pet) { %> 
        <li><%- pet.name %> (<%- pet.type %>)</li> 
       <% }); %> 
      </ul> 
     </script> 

     <div id="container"/> 

     <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script> 
     <script type="text/javascript" src="http://underscorejs.org/underscore.js"></script> 
     <script src="http://backbonejs.org/backbone-min.js"></script> 
     <script type="text/javascript"> 

      var serviceData = [ 
       { 
        name: "Peaches", 
        type: "dog" 
       }, 

       { 
        name: "Wellington", 
        type: "cat" 
       }, 

       { 
        name: "Beefy", 
        type: "dog" 
       } 
      ]; 

      $(document).ready(function() { 
       var Pet = Backbone.Model.extend({ 
        name: null, 
        type: null 
       }); 

       var Pets = Backbone.Collection.extend(); 

       var AppView = Backbone.View.extend({ 
        updateUi: function(model) { 
         _.templateSettings.variable = "model"; 
         var template = _.template($("script.template").html()); 
         var model = { pets: model.collection.toJSON() }; 
         var html = template(model); 
         $("#container").html(html); 
        } 
       }); 

       var pets = new Pets(); 
       var av = new AppView(); 
       pets.bind("add", av.updateUi); 
       pets.set(serviceData); 
      }); 

     </script> 
    </body> 
</html> 

回答

1

您需要在代碼上重新考慮幾件事情。對於您的特定情況,您需要使用重置而不是設置,以在數據設置時僅分派一個事件。您也可以將集合傳遞給視圖,並且視圖可以聽取重置事件。

此外,爲了防止瀏覽器的壓力,您可以使用document.createDocumentFragment,它是一個可以加速append處理的DOM持有者。檢查點二號更多參考: http://ozkatz.github.io/avoiding-common-backbonejs-pitfalls.html

<html> 
    <head> 
     <meta charset="utf-8" /> 
     <title>Looking At Underscore.js Templates</title> 
    </head> 
    <body> 
     <script type="text/template" class="template"> 
      <ul id="petlist"> 
       <% _.each(model.pets, function(pet) { %> 
        <li><%- pet.name %> (<%- pet.type %>)</li> 
       <% }); %> 
      </ul> 
     </script> 

     <div id="container"/> 

     <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script> 
     <script type="text/javascript" src="http://underscorejs.org/underscore.js"></script> 
     <script src="http://backbonejs.org/backbone-min.js"></script> 
     <script type="text/javascript"> 

      var serviceData = [ 
       { 
        name: "Peaches", 
        type: "dog" 
       }, 

       { 
        name: "Wellington", 
        type: "cat" 
       }, 

       { 
        name: "Beefy", 
        type: "dog" 
       } 
      ]; 

      $(document).ready(function() { 
       var Pet = Backbone.Model.extend({ 
        name: null, 
        type: null 
       }); 

       var Pets = Backbone.Collection.extend(); 

       var AppView = Backbone.View.extend({ 
        initialize : function(){ 
         this.collection.bind("reset", av.updateUi); 
        }, 
        updateUi: function() { 
         $items = document.createDocumentFragment(); 
         this.collection.each(function(model){ 
          var itemView = new ItemView({model : model}); 
          $items.append(itemView.el); 
          itemView.render(); 
         }); 
         $("#container").html($items); 
        } 
       }); 

       var pets = new Pets(); 
       var av = new AppView({collection : pets}); 
       pets.reset(serviceData); 
      }); 

     </script> 
    </body> 
</html> 
+0

真的很好回答,謝謝。 – d512 2013-04-08 15:17:56

3

你也可以創建一個名爲一個額外的方法,可以說,補充。 因此,如果添加一個新對象,應用程序只添加一個對象,而不是再次渲染孔集合。

事端這樣的:

App.Model = Backbone.Model.extend(); 

App.Collection = Backbone.Collection.extend({ 
    model: App.Model 
}); 

App.CollectionView = Backbone.View.extend({ 
    tagName: 'ul', 
    render: function(){ 
    this.collection.each(function(model){ 
     var objView = new App.ModelView({ model: model }); 
     this.$el.append(objView.render().el); 
    }); 
    return this; 
    }, 

    showAddForm: function(){ 
    // Here you show the form to add another object to the collection 
    }, 

    save: function(){ 
    // Take form's data into an object/array, then add it to the collection 
    var formData = { 
     type: $('select[name=type]').val(), 
     name $('input[name=name]').val() 
    }; 
    // Once added to the collection, take the object/array and... 
    this.addElement(formData); 
    }, 

    addElement: function(model){ 
    var modView = new App.ModelView({ model: model }); 
    this.$el.append(modView.render().el); 
    } 
}); 

App.ModelView = Backbone.View.extend({ 
    tagName: 'li', 
    template: _.template("<li><%= name %> (<%= type %>)</li>"), 

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

你明白我的意思? 渲染孔集合時,collectionView渲染方法爲每個對象/寵物調用modelView。 因此,通過這種方式,當您獲得新寵物/對象的信息時,您可以創建一個ModelView實例,並將其附加到實際渲染視圖。

希望它有幫助。

+0

而且,如果你想使一個隊列,你可以創建一個數組,推動所有新車型進去。當您完成加載數據時,點擊「保存更改」按鈕,並逐一添加li項目。 – Pablo 2013-04-05 20:43:34

+0

我喜歡這個解決方案,但我認爲martinkacmar的更適合我的特殊環境。儘管如此,我會在未來記住這一點。 – d512 2013-04-05 21:36:06

1

你也可以這樣做:

pets.set(serviceData, { silent: true }); 
pets.trigger('add', pets); 

並修改av.updateUi與全收集工作,並同時創建的HTML,但「復位」事件將可能更適合在這種情況下,不是「加」 。

+0

這更多的是我想到的。這裏唯一的缺點是,updateUI方法會根據您是渲染數組還是單個對象而獲得與模型不同的東西。不是一個大問題,而只是需要注意的事情。我通過做 var pets = model.collection? model.collection.toJSON():model.toJSON(); – d512 2013-04-05 21:29:19