【问题标题】:How to execute a callback after an #each is done?#each 完成后如何执行回调?
【发布时间】:2015-12-04 08:46:07
【问题描述】:

#each 完成后,我遇到了回调问题。我有一个名为“内容”的模板:

<template name="content">
{{#if Template.subscriptionsReady}}
    {{#each currentData}}
        <div data-cid="{{this._id}}"></div>
    {{/each}}
{{else}}
    Loading...
{{/if}}
</template>

首先我等待订阅,当订阅可用时,我使用{{#each}} 遍历我的集合并附加div。我需要的是当 for-each 循环完成时的一种回调(换句话说,DOM 准备好了)。

Template.content.onRendered()

-> 提前触发

我还尝试在 {{each}} 之后附加图像并在其onload 中触发一个函数,如下所示:

<img style="height:0;width:0" src="*mysource*" onload="callback()">

-> 有时确实有效,但不知何故不可靠

有没有办法得到这个回调?我不害怕改变这个模板的结构,如果能带来解决方案的话。

【问题讨论】:

  • 我不知道这是不是重复的,但它肯定和this question的感觉一样。

标签: javascript meteor spacebars


【解决方案1】:

我遇到了类似的问题,经过大量搜索找到了以下解决方案。我尝试使用TrackeronRendered 和其他技巧,但都没有奏效。这可能被认为更像是一种黑客行为,但有效。不幸的是,我不记得我最初在哪里找到了这个解决方案。

从您的模板开始,但在您的each 之后添加一个模板标签。

<template name="content">
{{#if Template.subscriptionsReady}}
    {{#each currentData}}
        <div data-cid="{{this._id}}"></div>
    {{/each}}
    {{doneTrigger}}
{{else}}
    Loading...
{{/if}}
</template>

然后定义一个返回 null 的助手。

Template.content.helpers({
  doneTrigger: function() {
    Meteor.defer(function() {
      // do what you need to do
    });
    return null;
  }
});

你可以阅读更多关于Meteor.defer()here的信息,但它相当于使用0毫秒setTimeout

【讨论】:

  • 它使用#each的同步特性。有趣,但可能无法在 Blaze 的进一步更新中幸存!
  • 确实,如前所述,在这一点上,我认为这更像是一种黑客行为。虽然它确实完成了工作。观看。
【解决方案2】:

考虑一种可能更简单的方法 - 在您的 #each 块周围创建一个模板,然后获取一个 onRendered 事件:

html:

<template name="content">
{{#if Template.subscriptionsReady}}
    {{> eachBlock}}
{{else}}
    Loading...
{{/if}}
</template>

<template name="eachBlock">
{{#each currentData}}
    <div data-cid="{{this._id}}"></div>
{{/each}}
</template>

js:

Template.eachBlock.onRendered(function(){
  console.log("My each block should now be fully rendered!");
});

【讨论】:

    【解决方案3】:

    您还可以使用子模板并计算呈现的子模板的数量。如果此数字是集合中的项目数,则全部呈现。

    <template name="content">
    {{#if Template.subscriptionsReady}}
        {{#each currentData}}
            {{> showData}}
        {{/each}}
    {{else}}
        Loading...
    {{/if}}
    </template>
    
    <template name="currentData">
      <div data-cid="{{this._id}}"></div>
    </template>
    

    这样,初始化一个反应变量并跟踪它:

    var renderedCount = new ReactiveVar(0);
    
    Tracker.autorun(function checkIfAllRendered() {
      if(renderedCount.get() === currentData.count() && renderedCount.get() !== 0) {
        //allDataRendered();
      }
    });
    

    currentData 模板被渲染时,递增,销毁时递减。

    Template.currentData.onRendered(function() {
      renderedCount.set(++renderedCount.curValue);
    });
    
    Template.currentData.onDestroyed(function() {
      renderedCount.set(--renderedCount.curValue);
    });
    

    【讨论】:

      【解决方案4】:

      当 Spacebars {{#each}} 块已将每个被迭代的项目渲染到 DOM 时,没有简单的方法来获得通知。

      最好的解决方案是使用另一个反应式计算 (Tracker.autorun) 来观察您的(反应式)当前数据。

      每次修改当前数据(可能是游标)时,您都可以使用Tracker.afterFlush 在其他所有响应式计算完成执行其工作后运行任意代码。

      {{#each}} 块是这些计算之一,它的作用是侦听您作为参数提供的反应性数据源,并重新渲染其 Template.contentBlock 与从源中获取的项目重复的次数一样多,其中当前项目作为当前数据上下文。

      通过监听与 {{#each}} 块帮助程序完全相同的反应数据源并在它完成自己的反应计算之后运行您的代码,您可以获得实际请求的行为,而无需依赖一些奇怪的技巧。

      这里是这个模式的完整实现:​​

      JS

      Template.content.helpers({
        currentData: function(){
          return Template.currentData();
        }
      });
      
      Template.content.onRendered(function(){
        this.autorun(function(){
          var cursor = Template.currentData();
          // we need to register a dependency on the number of documents returned by the
          // cursor to actually make this computation rerun everytime the count is altered
          var count = cursor.count();
          //
          Tracker.afterFlush(function(){
            // assert that every items have been rendered
            console.log(this.$("[data-cid]") == count);
          }.bind(this));
        }.bind(this));
      });
      

      【讨论】:

      • 我喜欢这个解决方案,我认为它易于使用,所以谢谢!我已经决定在 {{#each}} 中使用模板,因为我意识到每个项目之后的回调足以解决我的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 1970-01-01
      • 2018-10-30
      • 1970-01-01
      • 2013-07-07
      • 2012-07-01
      相关资源
      最近更新 更多