让骨干等待呈现视图

时间:2013-04-05 20:13:52

标签: backbone.js

我是骨干的新手,我有一组对象和一个将它们显示为列表的视图。它被设置为每次将对象添加到集合时都会重新呈现视图。这是非常低效的,因为如果我一次向集合中添加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>

3 个答案:

答案 0 :(得分: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实例,并将其附加到实际渲染视图。

希望它有所帮助。

答案 1 :(得分:1)

你也可以这样做:

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

修改av.updateUi以使用整个集合并立即创建HTML,但在这种情况下,'reset'事件可能比'add'更合适。

答案 2 :(得分:1)

您需要在代码上重新考虑一些因素。对于您的特定情况,您需要使用reset而不是set,以便在设置数据时仅调度一个事件。您也可以将集合传递给视图,视图可以监听重置事件。

此外,为了防止浏览器的压力,您可以使用document.createDocumentFragment,它是一个加速追加处理的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>