我有一些问题可以确定Meteor.rendered
的确如何运作。我正在尝试动画Meteor中的实时更改,非常像this question。每当我点击一个元素时,我都希望它闪烁。
但是,每次单击一个元素时,模板都会渲染两次,这反过来会触发动画两次。这是代码:
模板
<body>
{{> myItemList}}
</body>
<template name="myItem">
<div class="item {{selected}}">
<h4>{{name}}</h4>
<p>{{description}}</p>
</div>
</template>
<template name="myItemList">
{{#each items}}
{{> myItem}}
{{/each}}
</template>
的Javascript
Template.myItemList.helpers({
items: function () {
return Items.find();
}
});
Template.myItem.helpers({
selected: function () {
return Session.equals('selected', this._id) ? "selected" : "";
}
});
Template.myItem.events({
'click .item' : function () {
Session.set('selected', this._id);
}
});
Template.myItem.rendered = function () {
$(".item.selected").fadeOut().fadeIn();
};
我的理解是,每次调用Session.set
时,都会重新使用Session.get
用于同一个键的每个模板,如文档中所述。所以我的猜测是,不知怎的,Session.equals
会导致模板重播2次?如果我使用此代码更改selected
帮助程序:
Template.myItem.helpers({
selected: function () {
if (Session.get("selected")) === this._id)
return "selected";
else
return "";
}
});
然后动画被触发3次而不是2次。
考虑到所有这些,我的问题是:
Template.myItem.rendered
会被触发两次?幕后究竟发生了什么?所以评论@Xyand解决方案:
click
将动画移动到Meteor.setTimeout()
事件肯定有效,但对我来说感觉有些笨拙。解决方案实际上很简单,已在this question中给出。代码如下所示:
Template.myItem.rendered = function () {
if (Session.equals('selected', this.data._id))
$(this.firstNode).fadeOut().fadeIn();
};
我首先尝试使用具有不同模板标记的不同项目并且它不起作用,这就是我创建这个最小项目以查看出错的原因。事实证明,为了实现这一点,您绝对需要在myItem
模板中调用子模板myItemList
。如果模板看起来像这样,
<template name="myItemList">
{{#each items}}
<div class="item {{selected}}">
<h4>{{name}}</h4>
<p>{{description}}</p>
</div>
{{/each}}
</template>
因此为rendered
模板调用了每个辅助函数和myItemList
函数,代码将无法工作,因为在rendered
函数内,模板实例将具有{ {1}}未定义的属性。
答案 0 :(得分:1)
模板被渲染两次,因为渲染了同一模板的两个不同实例。一个将selected
更改为"selected"
,另一个将其更改为""
。这也解释了为什么在将equals
切换为get
时有3个渲染。
将命令式javascript与声明式混合总是一团糟。所以这是我的两个建议:
在if
函数中添加rendered
,以确保仅在所选项目模板实例中调用转换。
将转场移至事件本身。您可能需要使用Meteor.setTimeout
。
将转换置于rendered
可能不是最佳选择,因为每次模板渲染时都会发生转换。例如,如果name
发生变化。想想当代码变得更长时会发生什么......
答案 1 :(得分:0)
正如其他人所说,每次客户端获取另一部分数据时,模板都会被重新呈现,无论是因为数据发生了变化还是因为延迟。
值得庆幸的是,还有另一个在创建模板时只调用一次的函数,即 - template.created
。它有一个缺点,你不能从那里访问视图元素,因为它们尚未创建。但是,您可以将模板标记为“新鲜”并在下一个渲染上安排动画:
var animate;
Template.myItem.created = function() {
animate = true;
};
Template.myItem.rendered = function() {
if(animate) {
animate = false;
... // Do the animation here.
}
};
<强>更新强>
Template.myItem.events({
'click .item' : function () {
animate = true;
Session.set('selected', this._id);
},
});