在BackBone js中的渲染视图上调用javascript。后渲染回调?

时间:2012-02-04 23:48:22

标签: javascript view backbone.js

看,骨干视图呈现呼叫:

render: function() {
  $(this.el).html(this.template({title: 'test'}));  //#1
  this.renderScatterChart();
  return this;
},

所以,我在#1处调用标准渲染。然后,我调用一个方法[这次,它是图表lib的包装],寻找一个div。 div由渲染调用呈现。但是在这一点上,它还没有附加到DOM(对吧?)。所以图表召唤可悲地死了。

这是什么模式?我很高兴听到有一个后渲染回调。我已经尝试了几次黑客攻击,有时我会让图表工作,但事件并没有结合。

8 个答案:

答案 0 :(得分:45)

我通常采用的方法是使用setTimeout,超时为零,以便在浏览器再次获得控制权后安排某些事情发生。试试这个:

render: function() {
    $(this.el).html(this.template({title: 'test'}));

    var _this = this;
    setTimeout(function() {
        _this.renderScatterChart();
    }, 0);

    return this;
}

或者,如果renderScatterChart已经绑定到相应的this

render: function() {
    $(this.el).html(this.template({title: 'test'}));
    setTimeout(this.renderScatterChart, 0);
    return this;
}

如果您想更明确地了解自己的目标,还可以使用_.defer

  

推迟 _.defer(function, [*arguments])

     

延迟调用函数,直到当前调用堆栈清除为止,类似于使用 setTimeout ,延迟为0。

所以你也可以这样做:

// Assuming that `renderScatterChart` is bound to the appropriate `this`...
render: function() {
    $(this.el).html(this.template({title: 'test'}));
    _(this.renderScatterChart).defer();
    return this;
}

// or if it isn't bound...
render: function() {
    $(this.el).html(this.template({title: 'test'}));

    var _this = this;
    _(function() {
        _this.renderScatterChart();
    }).defer();

    return this;
}

答案 1 :(得分:26)

我知道这已经回答了,但我想我会分享。 Underscore js通过_.defer函数为您提供了这个功能。

render: function() {
    $(this.el).html(this.template({title: 'test'}));  //#1
    _.defer( function( view ){ view.renderScatterChart();}, this );
    return this;
},

根据Underscore文档,这与已接受的解决方案实际上是相同的。

答案 2 :(得分:3)

这是因为你在.el插入DOM之前运行渲染。检查我的自解释代码(在包含Backbone.js的空白页中运行):

function someThirdPartyPlugin(id){
   if( $('#' +id).length ===0  ){
    console.log('Plugin crashed');
   }else{
    console.log('Hey no hacks needed!!!'); 
   }
}

var SomeView = Backbone.View.extend({
    id : 'div1',
    render : function(){
      this.$el.append("<p>Hello third party I'm Backbone</p>");
      someThirdPartyPlugin( this.$el.attr('id') );
      return this;
  }
}); 
var SomeView2 = Backbone.View.extend({
    id : 'div2',
    render : function(){
      this.$el.append("<p>Hello third party I'm Backbone</p>");
      someThirdPartyPlugin( this.$el.attr('id') );
      return this;
  }
}); 

var myView1 = new SomeView();
$('body').append( myView1.render().el );
var myView2 = new SomeView2();
$('body').append( myView2.el );
myView2.render();

答案 3 :(得分:1)

你可以这样做(如果renderSactterChart在'jQuery-ized'对象上运行):

render: function() {
  this.$el.html(this.template({title: 'test'}));  //#1
  this.$el.renderScatterChart();
  return this;
},

(这不是实际的DOM元素......)

答案 4 :(得分:1)

与你一样的问题......使用highcharts。我正在使用Backbone.LayoutManager,并最终破解代码以添加postRender回调。很想将此视为Backbone.js的一部分

答案 5 :(得分:1)

如果您不想使用setTimeout hack,我认为这种方式更“正常”:

只需将$ el元素传递给需要操作render()添加的元素的函数,然后可以在$ el上完成DOM操作。

答案 6 :(得分:0)

这已经得到了回答,但为了将来的参考,我已经有过几次这个问题了。我通过添加自定义事件解决了这个问题,在这种情况下它可能类似于

render: function() {
  $(this.el).html(this.template({title: 'test'}));  //#1

  this.on('someView:append', function() {
      this.renderScatterChart();
  }, this);

  return this;
}

然后,当我将元素附加到DOM时,我会像

一样触发它
myView.trigger('someView:append');

现在,它肯定不是一个美丽的解决方案。您正在将触发此事件的责任添加到将呈现的视图附加到DOM的任何内容。根据您的代码结构如何,它可以更好或更差。同样,我只是将此作为未来参考和替代方案发布。

更多信息:http://backbonejs.org/#Events

答案 7 :(得分:0)

这应该这样做:

render: function() {
  Marionette.ItemView.prototype.render.apply(this, arguments);
  your code ...
}
带有牵线木偶的样本,但想法也适用于骨干视图