【问题标题】:MeteorJS: Loading... templates sequentiallyMeteorJS:按顺序加载...模板
【发布时间】:2017-03-12 06:36:25
【问题描述】:

所以,基本上,我有一个包含多个类别照片的集合。我目前有这样的设置来浏览类别并为每个类别加载一个模板:

{{#each categories}}
  {{>gallery collectionName=categoryName}}
{{/each}}

因此,这非常适合使用图库模板动态构建每个部分。

由于每个画廊都有自己的图像集合,我在画廊模板中添加了一个辅助函数来调用相应的集合,然后对于每个集合图像,将其添加到画廊。

(在图库模板内)

{{loadPhotos collectionName}}

现在,您可能会看到问题所在。

首先创建图库 div,为空,然后一次全部创建,所有照片都添加到所有 div 中。

我希望,每个画廊都显示一个加载圈,直到所有照片都添加完毕,然后下一个画廊开始加载照片,加载完所有照片后加载圈消失。这一直持续到所有类别都加载完毕。

如果有帮助,我正在使用 jquery 添加照片和 FlowRouter...

感谢您的宝贵时间和提供的任何解决方案!

【问题讨论】:

    标签: javascript meteor meteor-blaze


    【解决方案1】:

    过去我不得不做类似类型的事情,而我能够做到这一点的方式是创建一种在模板和子模板之间进行通信的方式。执行此操作的主要方法是将回调函数传递给每个子模板,或传递ReactiveVarReactiveDict 或任何其他父“监听”的响应式计算。我测试了以下方法,它应该可以完美地满足您的需求。

    首先是主要类别模板。

    <template name="photoGallery">
      {{#each cat in categories}}
        {{> gallery collectionName=cat.name loadNow=loadTrigger isLoaded=loadedIndicator}}
      {{/each}}
    </template>
    

    以及相关的 Javascript。请注意,对于这个例子,我订阅了一个名为photoCategories 的出版物,它从一个名为Categories 的集合中发布一组文档(其中包含name 属性中的画廊类别列表以及我希望它们加载的顺序loadOrder 属性)。 您的具体情况可能有所不同。

    import { Template } from 'meteor/templating';
    import { Categories } from '../../../api/categories/categories.js';
    import { ReactiveDict } from 'meteor/reactive-dict';
    import { ReactiveVar } from 'meteor/reactive-var';
    
    import './photoGallery.html';
    import '../utils/loading-indicator.html';
    
    Template.photoGallery.onCreated(function() {
      this.loadTrigger = new ReactiveDict('loadTrigger');
      this.lastLoaded = new ReactiveVar();
      this.loadOrder = [];
    
      // subscribe to category data and when complete build loading controls
      // in this example the collection that contains the categories is called
      // 'Categories' and each document contains a property called 'loadOrder'
      // to control the order to load the galleries
      this.subscribe('photoCategories', () => {
        // we are inside the 'onComplete' subscription callback
        Categories.find({}, {sort: {loadOrder: 1}}).forEach((category) => {
          // create a trigger for each gallery so we can communicate when to load
          // initialize each trigger to false for now
          this.loadTrigger.set(category.name, false);
    
          // we need to also keep track of our load order so we know which
          // gallery to trigger next
          this.loadOrder.push(category.name);
        });
    
        // now that everything is initialized, lets trigger the first gallery to load
        this.loadTrigger.set(this.loadOrder[0], true);
      });
    
      // re-runs everytime a gallery is finished loading
      this.autorun(() => {
        // get which gallery just finished loading
        var lastLoaded = this.lastLoaded.get();
        var lastLoadedIndex = this.loadOrder.indexOf(lastLoaded);
    
        // make sure we have more galleries to load
        if (lastLoadedIndex + 1 < this.loadOrder.length) {
          // get the next gallery to load
          var loadNext = this.loadOrder[lastLoadedIndex + 1];
    
          // trigger the gallery to load
          Tracker.afterFlush(() => {
            this.loadTrigger.set(loadNext, true);
          });
        }
      });
    });
    
    Template.photoGallery.helpers({
      // returns our photo gallery categories to iterate over in our template
      categories: function() {
        return Categories.find({}, {sort: {loadOrder: 1}});
      },
    
      // returns our ReactiveDict so we can communicate to our sub-template
      // galleries when they can load
      loadTrigger: function() {
        return Template.instance().loadTrigger;
      },
    
      // returns our ReactiveVar used to keep track of which gallery just loaded
      loadedIndicator: function() {
        return Template.instance().lastLoaded;
      },
    });
    

    基本上,我们在这里所做的是订阅包含类别列表的出版物。然后我们构建一个加载触发器字典,我们将使用它来触发每个画廊加载。我们还需要定义一个最后加载的触发器,以便我们知道画廊何时完成加载(并且可以触发下一个加载)。

    为确保这一切正常工作,我们需要确保将加载触发器和最后加载的触发器传递给图库模板(这样它们就可以被触发加载并在完成后指示回来)。

    现在让我们看看图库模板。

    <template name="gallery">
      {{#if okToLoadNow collectionName}}
        {{loadPhotos collectionName}}
      {{else}}
        {{> loading_indicator }}
      {{/if}}
    </template>
    

    以及相关的javascript。

    Template.gallery.helpers({
      // reactive checks if we are ok to load
      okToLoadNow: function(collectionName) {
        return Template.instance().data.loadNow.get(collectionName);
      },
    
      // contains logic that loads photos, renders them on the page, then triggers
      // back once the loading is complete
      loadPhotos: function(collectionName) {
        const instance = Template.instance();
    
        // insert the code that loads the photos and renders them on the page here!
        // if the logic is complete it probably makes more sense to put this in a sub-template
        // and put the logic in the `onRendered` callback
    
        // lets simulate loading by pausing for 3 seconds then communicate back
        // that we loaded
        Meteor.setTimeout(() => {
          instance.data.isLoaded.set(collectionName);
        }, 3000);
      },
    });
    

    在图库模板中,我们会显示一个加载指示器,直到我们被触发加载。一旦我们完成加载,我们就会指示(通过 isLoaded 触发器)我们已经完成了。为此,我们只需传回刚刚加载的画廊名称。

    正如我之前提到的,我能够测试这种方法是否有效。您应该能够根据自己的具体情况进行调整。

    告诉我进展如何!

    【讨论】:

    • 感谢代码建议。这有点工作。我目前遇到的问题是它会加载第一个画廊(指标工作),但随后卡在第二个画廊(指标不会消失)。在控制台中它说:TypeError: Cannot read property 'data' of null; at gallery.js:10; at Object.Tracker._runFlush 另外,我不确定如何调用this.getCategories 和排序PhotoCategories.find({}, {sort: {loadOrder: 1}}); 我假设loadOrder 是占位符?再次感谢!
    • 另外,我不确定,但lastLoaded 似乎没有重新设置为新变量。只是保持为 reactiveVar?
    • 对以上内容有什么想法吗?
    • 让我尝试一下我的解决方案,我会尽快回复您
    • @Daltron 我用适合我的解决方案更新了我的答案。我从原始版本中更改了一些内容,但由于我能够在本地对其进行测试,所以它现在对你来说应该可以了。
    猜你喜欢
    • 1970-01-01
    • 2015-11-08
    • 1970-01-01
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多