如果我想在渲染视图后调用一个jquery插件(例如,将一个表插入到dom中),除了使用window.setTimeout()执行此操作之外是否还有可能?
此代码完成工作(1ms超时;这很奇怪):
Route.HomeRoute = Ember.Route.extend({
renderTemplate: function() {
this.render("home"); // render the home view
window.setTimeout(function() {
$(".tables").insertTables(); // this would add a table
}, 1);
}
})
但是这段代码不起作用:
Route.HomeRoute = Ember.Route.extend({
renderTemplate: function() {
this.render("home"); // render the home view
$(".tables").insertTables(); // this would add a table
}
});
我知道有Ember.View.didInsertElement(),但因此我必须在父View上设置一个回调,并且只是想知道为什么上面的代码示例不能按预期工作。
非常感谢!
答案 0 :(得分:2)
我不知道我的回答是100%准确的,但我想这是可以解释的:
我想问题是,你认为render()方法同步完成它的工作。但这种情况并非如此。相反,它会安排HomeView的渲染。渲染计划在 Ember的RunLoop 中。在第二个示例中,您的代码会调度呈现,然后立即尝试访问其DOM元素(我猜.tables是主模板的一部分)。但是View目前还没有渲染!第一个示例有效,因为涉及1ms超时。 在此超时期间,Ember RunLoop将启动并启动其魔法。它执行渲染,之后当CPU再次释放时,可以调用超时功能。
实际上你想要做的是:do something on my DOM, when the View was successfully rendered
。这可以在Ember中完成,而无需使用setTimeout。以下代码访问RunLoop并安排在RunLoop结束时执行的函数。
Ember.run.next(function() {
$(".tables").insertTables(); // this would add a table
});
这是一篇关于RunLoop的文章,如果你想了解Ember的这些细节,这一点很重要。 - Article by machty
最后但并非最不重要:在路线中进行此类DOM操作时,接缝完全尴尬。你的路线应该永远是免费的。元素和选择器以及jQuery插件只应在View层中使用。其他一切似乎都很糟糕。也许您想分享有关您选择此方法的原因的更多详细信息?这个可能是更好的解决方案。
答案 1 :(得分:0)
第二个例子不起作用的原因可能是Ember.js Run Loop。 this.render
计划dom插入以便稍后在当前运行循环中使用。
DOM插入在运行循环结束时完成,并且通过使用setTimeout
,您在运行循环结束后调用插件,因此保证模板被注入DOM。 (不需要1ms,0ms可能会工作)
你可能会说这个运行循环非常复杂,特别是对于Ember.js初学者。理想情况下,它应该对应用程序开发人员透明。你遇到副作用的原因是因为DOM操作不应该在路由器中处理。
我的第一反应是告诉你使用didInsertElement
,或View中的任何代码或钩子,因为这是DOM操作应该发生的地方。但似乎你已经意识到这一点,并且由于某种原因不能使用它(我无法确认或否认,因为我没有足够的信息)。
我的建议,尽量在didInsertElement
中完成。