过去我不得不做类似类型的事情,而我能够做到这一点的方式是创建一种在模板和子模板之间进行通信的方式。执行此操作的主要方法是将回调函数传递给每个子模板,或传递ReactiveVar、ReactiveDict 或任何其他父“监听”的响应式计算。我测试了以下方法,它应该可以完美地满足您的需求。
首先是主要类别模板。
<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 触发器)我们已经完成了。为此,我们只需传回刚刚加载的画廊名称。
正如我之前提到的,我能够测试这种方法是否有效。您应该能够根据自己的具体情况进行调整。
告诉我进展如何!