Possible to append subviews once to grid in backbo

2019-08-03 22:59发布

问题:

I'm loading JSON data (array of objects) via service, onReady, and want to display this data in a grid. I have each row represented by a view.

        render: function(){
            var self = this;
            (self.collection.models).forEach( function(model){
                var rowView = new RowView({model: model});
                self.$el.append(rowView.render().el);
            });                
        }

Is it possible to build subviews and push them all at once to the DOM instead of going 1 by 1? Does the browser reflow & repaint happen on every append?

Ive seen all the ways people add subviews/children, but none of them solve the problem (frequent DOM access?) because this is just how backbone is built?

回答1:

Yeah, that can be done. Generate an html element with jQuery (using the view's tagName definition and attributes and all that) and then append everything to that. When you're done, swap out the current this.$el with the new one:

render: function(){

  // create in memory element
  var $el = $(this.tagName);
  // also get the `className`, `id`, `attributes` if you need them

  // append everything to the in-memory element
  this.collection.each(function(model){
    var rowView = new RowView({model: model});
    $el.append(rowView.render().el);
  });

  // replace the old view element with the new one, in the DOM
  this.$el.replaceWith($el);

  // reset the view instance to work with the new $el
  this.setElement($el);
}

That should do it.

Of course, you're going to see a bit of a flicker on the screen, depending on how fast the browser is and how large the change is. But this should get you down the road to do what you want.

More info about replaceWith: http://api.jquery.com/replaceWith/



回答2:

I think there's a simpler solution than @Derick's answer:

render : function () {

  var children = [];

  this.collection.forEach( function( model ) {

    var rowView = new RowView( { model : model } );

    children.push( rowView.render().el );

  } );


  this.$el.empty().append( children );


  return this;

}

http://jsfiddle.net/tXnTk/

Comments on code in @Derick's answer (my comments marked with "[JMM]:"):

render: function(){

  // [JMM]: You should already have this.el / this.$el, so there 
  // [JMM]: should be no need to mess with this.tagName, className, 
  // [JMM]: id, etc. Just store the child views in an array.

  // create in memory element
  var $el = $(this.tagName);
  // also get the `className`, `id`, `attributes` if you need them

  // append everything to the in-memory element
  this.collection.each(function(model){
    var rowView = new RowView({model: model});
    $el.append(rowView.render().el);
  });


  // [JMM]: Using replaceWith will wipe out event listener
  // [JMM]: registrations and other data associated with the
  // [JMM]: DOM element. That's why it's necessary to call
  // [JMM]: setElement() afterward. Since you already have
  // [JMM]: the DOM element and you just want to change the
  // [JMM]: content you might as well just empty it out and
  // [JMM]: append the new children.

  // replace the old view element with the new one, in the DOM
  this.$el.replaceWith($el);

  // reset the view instance to work with the new $el
  this.setElement($el);
}