2012-02-04 43 views
22

不料,一個骨幹視圖渲染調用:在BackBone js中渲染視圖時調用javascript。 post-render回調?

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

所以,我所說的標準呈現在#1。然後,我調用一個方法[這一次,它是一個圖表lib的包裝],它尋找一個div。該div由渲染調用渲染。但在這一點上,它不附加到DOM(右?)。所以圖表通知可悲地死亡。

這是什麼模式?我很樂意聽到有一個post-render回調。我已經嘗試了幾個黑客,有時我會讓圖表工作,但事件不會綁定。

回答

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; 
} 
+3

OMG。我完全不相信,這工作。 – whatbird 2012-02-05 05:10:38

+1

@whatbird:這個'setTimeout(...,0)'技巧只是建立一個函數,當你的JavaScript全部完成並且控制權返回給瀏覽器時被調用。因此,您的代碼將設置所有內容並將所有內容添加到DOM,然後瀏覽器接管並觸發延遲的功能。這個技巧有點破解,但很有用。 – 2012-02-05 05:51:55

+0

如果您在運行渲染前將view.el插入到DOM中,則不需要破解。我不喜歡使用setTimeout hack,在流量不錯的情況下,它永遠不需要。檢查我的答案,解釋在插入.el之前運行呈現的差異並在插入後運行。一次運行崩潰,另一次正常運行,沒有setTimeout攻擊。 ;) – 2012-07-19 19:51:34

1

你可以這樣做(如果renderSactterChart在'jQuery-ized'對象上運行):

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

(這不是真正的DOM元素...)

1

有同樣的問題,因爲你做...與highcharts。我正在使用Backbone.LayoutManager,並最終黑客代碼添加postRender回調。很想看到這是Backbone.js的一部分

0

這個問題已經得到解答,但爲了將來的參考,我已經有過幾次這個問題。我解決它通過添加自定義事件,在這種情況下,它可能會像

​​

然後,當我的元素追加到DOM,我觸發它像

myView.trigger('someView:append'); 

現在,它肯定不是一個美麗的解決方案。您將觸發此事件的責任添加到將呈現視圖附加到DOM的任何內容。根據您的代碼結構如何,它可以更好或更差。再次,我只是將其作爲未來的參考和備選。

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

26

我知道這是回答,但想到我會分享。下劃線js使用_.defer函數覆蓋了你。

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

根據Underscore文檔,這與接受的解決方案實際上是相同的。

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(); 
1

如果你不想使用setTimeout劈,我覺得這種方式是比較「正常」:

只需將$ el元素傳遞給需要操作由render()添加的元素的函數,然後可以在$ el上完成DOM操作。

0

這項工作應像這樣:用木偶

render: function() { 
    Marionette.ItemView.prototype.render.apply(this, arguments); 
    your code ... 
} 

樣品,但思想工作骨幹的意見,以及

相關問題