【问题标题】:Meteor #each loop readyMeteor #each 循环准备就绪
【发布时间】:2015-05-28 03:51:47
【问题描述】:

我想知道有没有办法知道#each 循环是否“准备好”。 “就绪”是指它渲染所有节点并插入到 DOM 中。我什至不谈论onRendered 回调(旧的rendered)。我试过了

<template name="myTemplate">
<div class="some-class">
    {{#if Template.subscriptionsReady}}
       {{#each messages}}
          <div>{{text}}</div>
       {{/each}}
       <script>
           $(".some-class").trigger("LOOP_READY")
       </script>
    {{/if}}
</div>
</template>


Template.myTemplate.onRendered(function(){
    this.$(".some-class").on("LOOP_READY", doSomething)
})

但它也不起作用。我不想使用计时器。

更新

messages 是当前对话的文本消息集合,dialogId 是存储在Session 中的反应变量。

Template.myTemplate.onCreated(function(){
    var self = this;
    self.autorun(function(){
        self.subscribe("messages", Session.get("dialogId"))
    })
})

因此,如果有人更改了 dialogId,myTemplate 会加载另一个对话框消息,我想知道这些消息何时准备好,以滚动到特定消息。简单的onReady 不起作用,因为在所有消息都呈现并获得自己的高度之前,我无法准确地调用 scrollTop。

【问题讨论】:

  • 你确定onRenderedwaitOn (见铁路由器)或类似的不起作用吗?我可以想象您看到的触发器是从模板第一次呈现时开始的,即当还没有数据可用时。而且我怀疑您希望它仅在数据到达并且所有each 都已呈现时触发。你在等数据吗?
  • @ZuzEL 你能解释一下你为什么想要这个吗?需要初始化插件什么的吗?
  • 我认为,如果我得到你想要的,你的 scrollToTop 在新元素被添加之前就被触发了。所以从技术上讲,如果你只是破解并将 scrollToTop 放入 setTimeout(func,0) 调用中,当你调用 scroll 时元素高度将被更新。

标签: javascript meteor meteor-blaze


【解决方案1】:

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

最好的解决方案是使用另一个响应式计算 (Tracker.autorun) 来观察消息光标的变化。

每次修改您的消息列表时,您都可以使用Tracker.afterFlush,在其他所有反应式计算完成后运行任意代码。

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

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

这是该模式的完整实现:​​

HTML

<template name="myTemplate">
  <div class="some-class">
    {{#if Template.subscriptionsReady}}
      {{#each messages}}
        <div class="message">{{text}}</div>
      {{/each}}
    {{/if}}
  </div>
</template>

JS

// declare your reactive data source once to reuse the same in multiple places
function messagesCursor(){
  return Messages.find();
}

Template.myTemplate.helpers({
  messages: messagesCursor
});

Template.myTemplate.onRendered(function(){
  this.autorun(function(){
    // 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 messagesCount = messagesCursor().count();
    //
    Tracker.afterFlush(function(){
      // assert that every messages have been rendered
      console.log(this.$(".messages") == messagesCount);
    }.bind(this));
  }.bind(this));
});

【讨论】:

  • 谢谢,很好的解决方案。我将对此进行测试。我担心如果计算完成并不意味着所有元素都已插入 DOM。仅供参考,我实现了这样的行为,在自动运行功能中创建了一个间隔。看我的回答。
  • 好的,你的回答很好,但是因为我不想每次有新消息到达时都滚动到特定的消息,所以我不能使用它。查看我的解决方案。
【解决方案2】:

@saimeunt 提供了优雅的解决方案,但我以其他方式实现了它,也许有人觉得它也有帮助。

由于我不希望每次有新消息到达时都执行我的代码,所以我无法在自动运行完成后触发滚动。 (你会说,好吧,在只依赖于dialogId 的自动运行中执行。-然后我无法获得此对话框的确切消息数,因为订阅需要一些时间)

HTML

<template name="myTemplate">
  <div class="chat">
    {{#if Template.subscriptionsReady}}
      <div class="messages">
          {{#each messages}}
            <div class="message">{{text}}</div>
          {{/each}}
      </div>
      <script>$(".chat").trigger("MESSAGES_READY_EVENT")</script>
    {{/if}}
  </div>
</template>

JS

Template.chat.onCreated(function () {
    var self = this;
    self.messages = function() {
        return Messages.find({dialogId:Session.get("dialogId")})
    }
    self.autorun(function(){
        self.subscribe("messages", Session.get("dialogId"));
    })
});
//helpers skipped
Template.chat.onRendered(function () {
    var self = this;
    self.$(".chat").on("MESSAGES_READY_EVENT", function () {
        var computationNumber = 0;
        var $messages = self.$(".messages");
        //how many massages we have to render
        var total = self.messages().count();
        //max tries
        var maxTries = 10;
        var intervalId = Meteor.setInterval(function () {
            var totalNodes = $messages.children().length;
            if (computationNumber++ >= maxTries || total <= totalNodes) {
                Meteor.clearInterval(intervalId);
                $messages.scrollTop(someValue);
            }
        }, 100);
    });
});

【讨论】:

    猜你喜欢
    • 2015-04-30
    • 2012-02-15
    • 1970-01-01
    • 2013-02-14
    • 2019-10-09
    • 2017-07-05
    • 2015-07-01
    • 2017-12-02
    • 1970-01-01
    相关资源
    最近更新 更多