如何在 Ember 中(重新)渲染视图模板时收到通知?

Posted

技术标签:

【中文标题】如何在 Ember 中(重新)渲染视图模板时收到通知?【英文标题】:How to be notified when a view's template is (re)rendered in Ember? 【发布时间】:2013-12-09 10:15:52 【问题描述】:

当视图的模板由于模型的变化而被刷新时,didInsertElement 钩子不会被触发,因为 Ember 会尽可能地重用视图。这给我带来了一些问题,因为我需要在重新呈现模板时选择列表的第一个元素。例如,当从服务器加载新数据或应用程序转换到不同的路由时,就会发生这种情况。

奇怪的是,当应用程序转换到不同的路由时,视图的init 方法确实被调用了。问题是该模板还没有被渲染,也就是说,视图还没有被控制器的新内容填充。

简而言之,如何在视图模板完成重新渲染后通知我,以便我可以操作视图的内容?

请注意,观察控制器的模型也不是一种选择,因为在触发回调时视图尚未更新。

<script type="text/x-handlebars" id="list">
<div>
  <ul>
  #each model.items
    <li class="item">
      <p>title</p>
    </li>
  /each
  </ul>
</div>
</script>

更新 重新渲染each 块时需要通知视图。我想使用this question 中的解决方案,但似乎只有each 块被重新渲染,而不是整个模板(这是我想要的)。我可以在每个块中添加一个触发事件,但这非常昂贵,因为自定义事件将在each 块的每个循环中触发。

【问题讨论】:

您能否显示您想知道何时重新渲染的视图/模板的代码? Ember 只是重新渲染执行更改的 html 部分,因此如果您的 #each 正在更改,则只有 EachView 实例将收到重新渲染事件,而不是整个 @987654329 @。这是为 ember 提供的优化之一。 @MárcioRodriguesCorreaJúnior 我明白了,但是当EachView 被重新渲染时如何通知ListView 看看我的回答,也许能帮上忙 【参考方案1】:

也许这可行:

App.ListView = Ember.View.extend(
    templateName: 'list',
    contentChanged: function() 
        Ember.run.scheduleOnce('afterRender', this, 'selectFirstElement')
    .observes('controller.content.[]'),
    selectFirstElement: function() 
        // for simplicity
        this.$('li:first').addClass('selected');
    
);

使用observes('controller.content.[]') 调用contentChanged 函数,如果在控制器内容中执行了一些更改。为了不在同一个runloop中多次调用该函数,我们使用Ember.run.scheduleOnce('afterRender', ...),所以selectFirstElement只被调用一次,因为它被安排在afterRender队列中,你可以操纵dom。

现场演示http://jsfiddle.net/marciojunior/4b2V3/

【讨论】:

这太棒了。这绝对不是一个简单的解决方案,但它非常有效,尤其是在添加 scheduleOnce 时。【参考方案2】:
App.MagicView = Ember.View.extend(
  doMagic: function() 
    // magic goes here
  .on('didInsertElement');
);

更新:我现在明白了。这是我的大脑转储:http://emberjs.jsbin.com/URidoBi/3/edit。不是最干净的方法,但应该可以解决问题。

【讨论】:

由于问题中概述的原因,这不起作用。重新呈现视图的模板时,不会调用 didInsertElement 挂钩。如果可以,Ember 将重用视图,这意味着在重新渲染视图时不会调用 didInsertElement 挂钩。

以上是关于如何在 Ember 中(重新)渲染视图模板时收到通知?的主要内容,如果未能解决你的问题,请参考以下文章

Ember.js 的视图层

如何在加载模型时在Ember中显示加载模板?

使用 Ember.js 按模型类型/对象值选择视图模板

使用 Ember.js,如何在渲染视图后运行一些 JS?

在 emberjs 中重新渲染视图

AngularJS 具有相同模板的多个路由不应重新渲染