ember.js route render:使用setTimeout()进行dom操作?

时间:2013-03-21 08:24:27

标签: dom ember.js router

如果我想在渲染视图后调用一个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上设置一个回调,并且只是想知道为什么上面的代码示例不能按预期工作。

非常感谢!

2 个答案:

答案 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 Loopthis.render计划dom插入以便稍后在当前运行循环中使用。

DOM插入在运行循环结束时完成,并且通过使用setTimeout,您在运行循环结束后调用插件,因此保证模板被注入DOM。 (不需要1ms,0ms可能会工作)

你可能会说这个运行循环非常复杂,特别是对于Ember.js初学者。理想情况下,它应该对应用程序开发人员透明。你遇到副作用的原因是因为DOM操作不应该在路由器中处理。

我的第一反应是告诉你使用didInsertElement,或View中的任何代码或钩子,因为这是DOM操作应该发生的地方。但似乎你已经意识到这一点,并且由于某种原因不能使用它(我无法确认或否认,因为我没有足够的信息)。

我的建议,尽量在didInsertElement中完成。