2013-04-05 105 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