看,骨干视图呈现呼叫:
render: function() {
$(this.el).html(this.template({title: 'test'})); //#1
this.renderScatterChart();
return this;
},
所以,我在#1处调用标准渲染。然后,我调用一个方法[这次,它是图表lib的包装],寻找一个div。 div由渲染调用呈现。但是在这一点上,它还没有附加到DOM(对吧?)。所以图表召唤可悲地死了。
这是什么模式?我很高兴听到有一个后渲染回调。我已经尝试了几次黑客攻击,有时我会让图表工作,但事件并没有结合。
答案 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的任何内容。根据您的代码结构如何,它可以更好或更差。同样,我只是将此作为未来参考和替代方案发布。
答案 7 :(得分:0)
这应该这样做:
render: function() {
Marionette.ItemView.prototype.render.apply(this, arguments);
your code ...
}
带有牵线木偶的样本,但想法也适用于骨干视图