1

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

非常感谢!

4

2 回答 2

2

我不知道我的答案是否 100% 准确,但我想这就是它可以解释的方式:

我想问题是,您认为 render() 方法是同步完成其工作的。但这种情况并非如此。相反,它会安排 HomeView 的呈现。渲染被安排到 Ember 的 RunLoop 中。在第二个示例中,您的代码安排渲染,然后立即尝试访问其 DOM 元素(我猜 .tables 是主模板的一部分)。但是此时没有渲染视图!第一个示例有效,因为涉及 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 的那些细节,了解这篇文章很重要: - machty 的文章

最后但同样重要的是:在 Route 中进行这样的 DOM 操作非常尴尬。你的路线应该永远是免费的,这些东西。元素和选择器以及 jQuery 插件只能在视图层中使用。其他一切似乎都很糟糕。也许你想分享更多关于你为什么选择这种方法的细节?可能有比这个更好的解决方案。

于 2013-03-21T09:28:26.757 回答
0

第二个示例不起作用的原因可能是由于Ember.js Run Loopthis.render安排在当前运行循环中稍后插入 dom。

DOM 插入是在 run loop 结束时完成的,通过 using setTimeout,您在 run loop 结束后调用插件,从而保证模板被注入到 DOM 中。(不需要 1ms,0ms 可能会起作用)

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

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

我给你的建议,尽你所能在didInsertElement.

于 2013-03-21T09:29:18.100 回答