3

自从我升级到 0.8.0 后,我遇到了一个问题。渲染的模板不再被触发(第一次除外)。

我遵循了以下建议: https ://github.com/avital/meteor-ui-new-rendered-callback/blob/master/new2/client/each.js

这没有帮助,所以我最终制作了一小段代码(通过修改 new2 示例)。

主要区别在于更新是由 Session 变量更改而不是 DB 更改触发的。

这完美地显示了问题,因为在此示例中仅触发了两次渲染:

客户端/each.js

Template.list.items = function () {
  return (Session.get('items') || 'None')
};

var renderCount = 1;
var logRender = function () {
  console.log("rendered #" + renderCount);
  renderCount++;
};

Template.list.rendered = function () {
  logRender();
};

Template.justName.rendered = function () {
  logRender();
};

setInterval(function () {
  Session.set('items', {name: Random.choice(["one", "two", "three"])});
}, 1000);

客户端/each.html

<body>
  {{> list}}
</body>

<template name="list">
   {{#with items}}
   {{> justName}}
   {{/with}}
</template>

<template name="justName">
  {{name}}
</template>

当 Session.set 触发内容更新时,如何正确触发 Template.justName.rendered 回调?

谢谢,

4

3 回答 3

3

我确实为您提供了一个即时解决方案,但它可能需要一点点重新考虑您的实际代码。顺便说一句,这与这里的问题相同:

Meteor 0.8.0 - 无法在渲染回调中操作 DOM

但是这个问题是在如此不同的背景下提出的,所以回答两次是有意义的。

那么为什么它不触发渲染的回调呢?因为它不会重新渲染。

Blaze 以非常不同的方式对待“如何对更改的依赖项做出反应”这一整件事,“更好”的人可能会说:它将识别您的“一”、“二”或“三”所在的 DOM 节点(在您的情况下,它是模板本身)被存储在并只是替换已更改的部分,即文本内容“一”、“二”或“三”。DOM 节点本身以及模板保持完整。这也意味着,在几乎所有实际场景中,您可以使用此 DOM 节点执行的所有操作都不必重新执行。即,如果您对其进行动画处理,使用 jQuery 更改它的文本颜色,颜色和动画将仅保留在屏幕上,因此您不需要渲染回调来重新执行此操作。

在您的情况下,只需重新安排您想要在“重新渲染”上执行的操作即可轻松解决问题:

var whatever = function(){
    // whatever you want to do on data-change, in your case calling "logRender" (which needs to be renamed with Blaze, anyway..)
    logRender();
}

然后你唯一需要做的就是在你的数据发生变化时触发它,或者手动,像这样:

setInterval(function () {
    Session.set('items', {name: Random.choice(["one", "two", "three"])});
    // calling the function when changing the data, knowing that it WON'T destroy the DOM node it affects
    whatever();
}, 1000);

或被动地,像这样:

Deps.autorun(function(){
    Session.get("items"); // our dependency, just has to be there, but you can also use it
    whatever(); // will be fired whenever dependency changes
});

核心思想是消除在渲染回调中重新执行某些操作的需要,因为 DOM 及其对象的身份(以及所有漂亮的 jQuery 效果)仍然完好无损。所以剩下要做的就是只取决于特定的反应性数据更改,这就是为什么有Deps.autorun().

在您的特定示例中,您的“logRender”函数没有任何反应性依赖项,但如果您添加一些并将其放入 中Deps.autorun(),只要依赖项发生变化,它就会可靠地重新运行。

总而言之,Meteor 0.7.x 及以下版本让我们犯了将“渲染”回调函数视为通用自动运行函数的错误,这就是为什么我们现在遇到麻烦并且必须修复我们的应用程序的原因。

于 2014-04-01T19:38:10.860 回答
0

所以,我昨天做了很多挖掘,试图找出你遇到的基本完全相同的问题。我仍在挖掘,但我确实遇到了这个 Devshop Talk about Integrating Other Clientside JS Libraries。在其中 Ted Blackman 描述了他制作的一个包,用于在 Session 变量更改时触发事件。这听起来像你需要的。该演讲是在 0.8.0 之前进行的,因此我不确定该软件包将如何受到影响,但可能值得一试。

Devshop 谈话 - https://www.youtube.com/watch?v=NdBPY98o6eM

会话附加 - https://atmospherejs.com/package/session-extras

事件视界 - https://atmospherejs.com/package/event-horizo​​n

于 2014-04-02T14:22:08.060 回答
0

正如评论中所指出的,这确实是 Meteor 的设计更改。

在 Meteor 0.8 之前,模板是一个生成 HTML 的函数。每当它的任何反应性依赖项发生变化时,都会重新计算该函数,从而重新创建由模板生成的所有 DOM 节点(除了任何子模板或孤立节点)。每当重新绘制发生时,rendered就会触发回调。

这种行为对性能造成了相当大的影响,因为它需要重新渲染可能大量的 HTML,包括标识符和帮助程序,具体取决于未更改的数据。此外,使用 jQuery 等其他库来修改创建的 DOM 元素变得很困难,因为 Meteor 基本上可以控制整个过程,并且每次都必须小心地重新运行 jQuery 代码。

Meteor 0.8 通过仅渲染实际更改的 DOM 片段来解决此问题,直至模板中标识符的粒度——它的粒度要细得多。因此,模板的rendered回调仅在模板点击页面时触发一次,之后不再调用。这解决了很多性能问题,并允许 jQuery 和其他 DOM 操作与 Meteor 无缝协作,但也意味着当某些事情发生变化时您不会收到自动回调信号。但是,您可以通过使用反应变量来处理发生变化的特定事物的助手来实现这一点。

有关 Spacebars(新的 Handlebars 替代品)如何工作的更详细列表,请参阅https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md

另请参阅有关呈现回调的新文档:http: //docs.meteor.com/#template_rendered

于 2014-04-01T19:44:14.003 回答