当所有模板项目在 Meteor 中完成渲染时回调? [英] Callback when all Template items finished rendering in Meteor?
问题描述
我正在获取一组记录并将它们放置在模板中,让它们呈现 {{#each}}
并且我想显示一个加载图标,直到呈现最后一个 DOM 节点.
I'm getting a collection of records and placing them in a Template, having them rendered {{#each}}
and I want to display a loading icon until the last DOM node is rendered.
我的问题是我还没有找到一种方法来查询状态/触发最后一项呈现的回调,也就是最后一个要更新/重新绘制的 DOM 节点.
My problem is that I have not found a way to query a state/fire a callback on the last item rendered aka the last DOM node to be updated/re-drawn.
它在我的 HTML 文件中看起来有点像这样:
It looks a bit like this in my HTML file:
<template name="stuff">
{{#each items}}
<div class="coolView">{{cool_stuff}}</div>
{{/each}}
</template>
在客户端JS文件中:
// returns all records of Stuff belonging to the currently logged-in user
Template.stuff.items = function () {
Session.set('loading_stuff', true);
return Items.find({owner: Meteor.userId()}, {sort: {created_time: -1}});
};
Template.stuff.rendered = function() {
// every time something new is rendered, there will have been loading of the DOM.
// wait a short while after the last render to clear any loading indication.
Session.set('loading_stuff', true);
Meteor.setTimeout(function() {Session.set('loading_stuff', false);}, 300);
};
Session 变量 loading_stuff
在 Handlebars 助手中被查询,如果它是 true
,则返回加载类的名称(带有加载器图标 GIF).
The Session variable loading_stuff
is queried in a Handlebars helper, returning the name of the loading class (with a loader icon GIF) if it's true
.
我做这个笨拙的Meteor.setTimeout
的原因是因为Template.rendered
在每个渲染到模板的项目之后被调用.所以我需要重新确认它仍在加载,但给它一些时间来加载下一个或完成全部渲染,稍等片刻,直到将 loading_stuff
设置为 错误
.
The reason I do the awkward Meteor.setTimeout
is because Template.rendered
is called after every single item that was rendered into the Template. So I need to re-confirm that it is still loading, but give it some time to either load the next one or to finish rendering them all, with a little pause until it sets loading_stuff
to false
.
如何在所有 DOM 更新(针对特定模板或整个页面)结束时以正确的 Meteor 方式可靠地查询/回调?
How do I reliably query/callback at the end of all DOM updates (for a particular Template or for the whole page) the proper Meteor way?
非常感谢.
编辑
使用 subscribe()
onReady 的解决方案()
回调仅部分起作用:
The solution with using the subscribe()
onReady()
callback only partially works:
在渲染开始之前,模板似乎被多次调用 (2-3),但是 之后 数据从模板依赖渲染的服务器返回.这意味着它已完成"加载数据,但 DOM 仍在呈现.我将尝试使用 Meteor.autorun()
并查看是否可以在某处找到可靠的钩子来正确执行此操作.与此同时,我想我原来的问题仍然存在:
Templates are seemingly called multiple (2-3) times before the rendering even starts, but after the data has returned from the server that the Template relies on to render. This means that that it's 'finished' loading data, but the DOM is still being rendered. I will play around with Meteor.autorun()
and see if I can find a reliable hook somewhere to do this properly. In the meantime, I guess my original question still remains:
我如何知道整个模板/页面何时完成渲染?
How do I know when the entire Template/page has finished rendering?
最终
归根结底,基于 DOM 的结构,开发人员有一个坚如磐石的 DOM 并尽可能将适当的回调附加到他/她想要检查其状态的元素上.这似乎是一个反气候的不费吹灰之力,但对我来说,知道模板的最终元素被渲染的唯一方法是在模板的最后渲染一个具有特殊 id 的元素,该元素表示模板的结束渲染并附加一个 .livequery
回调到它.我希望 Meteor 将来能够为检查此状态提供更加统一和全球性的支持.
At the end of the day, based on how the DOM is structured, it's up to the developer have a rock-solid DOM and attach the appropriate callbacks as best as possible to the elements he/she wants to check the state of. It may seem like an anti-climatic no-brainer, but for me the only way to know the final element of a Template is rendered is to have an element with a special id rendered at the very end of a Template that signals the end of the render and attach a .livequery
callback to it. I hope that Meteor will incorporate a more unified and global support for checking this state in the future.
推荐答案
我发现在等待模板中的元素写入 DOM 时,JQuery 的 livequery 插件不起作用.这是因为该插件侦听 append 等 JQuery 方法,但 Meteor 不使用 JQuery.它使用一个名为 LiveRange
的对象来写入 DOM.我修改了我的 livequery JavaScript 文件来处理这个.
I found that JQuery's livequery plugin doesn't work when waiting for elements from a template to be written to the DOM. This is because the plugin listens on JQuery methods like append, but Meteor doesn't use JQuery. It uses an object called LiveRange
to write to the DOM. I modified my livequery JavaScript file to work with this.
在文件底部附近,有一行调用 registerPlugin()
.我把它修改成这样:
Near the bottom of the file, there is a line that calls registerPlugin()
. I modified it to look like this:
$.livequery.registerPlugin([
{object: $.fn, methods: ['append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove', 'html']},
{object: LiveRange.prototype, methods: ['insertBefore', 'insertAfter']}
]);
然后我将 registerPlugin() 方法修改为如下所示:
Then I modified the registerPlugin() method to look like this:
registerPlugin: function(registration) {
for (var i = 0; i < registration.length; i++) {
var object = registration[i].object;
var methods = registration[i].methods;
$.each( methods, function(i,n) {
// Short-circuit if the method doesn't exist
if (!object[n]) return;
// Save a reference to the original method
var old = object[n];
// Create a new method
object[n] = function() {
// Call the original method
var r = old.apply(this, arguments);
// Request a run of the Live Queries
$.livequery.run();
// Return the original methods result
return r;
}
});
}
}
这将检查在 LiveRange
对象上调用 insertBefore()
或 insertAfter()
时元素是否存在,并且仍然会像以前一样使用 JQuery.
This will check to see if the element exists when insertBefore()
or insertAfter()
is called on the LiveRange
object and will still work with JQuery as it did before.
这篇关于当所有模板项目在 Meteor 中完成渲染时回调?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!