MeteorJS:按顺序加载...模板
MeteorJS: Loading... templates sequentially
所以,基本上,我有一个包含多个类别照片的集合。我目前有这个设置来浏览类别并为每个类别加载模板:
{{#each categories}}
{{>gallery collectionName=categoryName}}
{{/each}}
因此,这非常适合使用图库模板动态构建每个部分。
由于每个图库都有自己的图片集,因此我在图库模板中添加了一个辅助函数来调用相应的图片集,然后针对每个图片集将其添加到图片库中。
(在图库模板内)
{{loadPhotos collectionName}}
现在,您大概可以看出问题所在了。
首先创建图库 div,为空,然后一次性将所有照片添加到所有 div。
我更愿意,每个图库都显示一个加载圆圈,直到所有照片都添加完毕,然后下一个图库开始加载照片,加载完所有照片后加载圆圈消失。这一直持续到所有类别都已加载。
我正在使用 jquery 添加照片和 FlowRouter,如果有帮助的话...
感谢您的宝贵时间和提供的任何解决方案!
我过去不得不做类似类型的事情,而我能够做到的方式是创建一种在模板和子模板之间进行通信的方式。执行此操作的主要方法是将回调函数传递给每个子模板,或者传递 ReactiveVar
、ReactiveDict
或父对象 "listening" 的任何其他反应式计算。我测试了以下方法,它应该可以完美满足您的需求。
首先是主要类别模板。
<template name="photoGallery">
{{#each cat in categories}}
{{> gallery collectionName=cat.name loadNow=loadTrigger isLoaded=loadedIndicator}}
{{/each}}
</template>
以及关联的 Javascript。请注意,在这个例子中,我订阅了一个名为 photoCategories
的出版物,该出版物从一个名为 Categories
的集合中发布了一组文档(其中包含 name
[=43 中的画廊类别列表) =] 和我希望它们在 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 触发器)我们已经完成了。为此,我们只传回刚刚加载的图库名称。
正如我之前提到的,我能够测试这种方法是否有效。您应该能够根据自己的具体情况对其进行调整。
让我知道进展如何!
所以,基本上,我有一个包含多个类别照片的集合。我目前有这个设置来浏览类别并为每个类别加载模板:
{{#each categories}}
{{>gallery collectionName=categoryName}}
{{/each}}
因此,这非常适合使用图库模板动态构建每个部分。
由于每个图库都有自己的图片集,因此我在图库模板中添加了一个辅助函数来调用相应的图片集,然后针对每个图片集将其添加到图片库中。
(在图库模板内)
{{loadPhotos collectionName}}
现在,您大概可以看出问题所在了。
首先创建图库 div,为空,然后一次性将所有照片添加到所有 div。
我更愿意,每个图库都显示一个加载圆圈,直到所有照片都添加完毕,然后下一个图库开始加载照片,加载完所有照片后加载圆圈消失。这一直持续到所有类别都已加载。
我正在使用 jquery 添加照片和 FlowRouter,如果有帮助的话...
感谢您的宝贵时间和提供的任何解决方案!
我过去不得不做类似类型的事情,而我能够做到的方式是创建一种在模板和子模板之间进行通信的方式。执行此操作的主要方法是将回调函数传递给每个子模板,或者传递 ReactiveVar
、ReactiveDict
或父对象 "listening" 的任何其他反应式计算。我测试了以下方法,它应该可以完美满足您的需求。
首先是主要类别模板。
<template name="photoGallery">
{{#each cat in categories}}
{{> gallery collectionName=cat.name loadNow=loadTrigger isLoaded=loadedIndicator}}
{{/each}}
</template>
以及关联的 Javascript。请注意,在这个例子中,我订阅了一个名为 photoCategories
的出版物,该出版物从一个名为 Categories
的集合中发布了一组文档(其中包含 name
[=43 中的画廊类别列表) =] 和我希望它们在 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 触发器)我们已经完成了。为此,我们只传回刚刚加载的图库名称。
正如我之前提到的,我能够测试这种方法是否有效。您应该能够根据自己的具体情况对其进行调整。
让我知道进展如何!