Meteor 0.8.0 - 无法在渲染回调中操作 DOM [英] Meteor 0.8.0 - Failed to operate DOM in rendered callback
问题描述
在 0.8.0 之前,以下代码完美运行.
<!--这里我使用了 Bootstrap 的轮播--><div id="myCarousel" class="carousel"><ol class="carousel-indicators">{{#每个计数器}}<li data-target="#myCarousel" data-slide-to="{{this}}"></li>{{/每个}}</ol><div class="carousel-inner">{{#每个轮播}}<div class="item"><a href="{{link}}"><img src="{{src}}" ></a></div>{{/每个}}
<a class="carousel-control left" href="#myCarousel" data-slide="prev">‹</a><a class="carousel-control right" href="#myCarousel" data-slide="next">›</a>
模板>Template.carousel.helpers({轮播:功能(){返回 Carousels.find();},计数器:函数(){返回 _.range(0, Carousels.find().count());}});Template.carousel.rendered = function() {流星.延迟(功能(){$('#myCarousel .carousel-indicators li:first').addClass('active');$('#myCarousel .item:first').addClass('active');});}
但是在更新到 0.8.0 之后,添加 'active' 类不再起作用.使用 Meteor.setTimeout 代替 Meteor.defer,我终于发现它只有在延迟足够长(有时超过 150ms)时才有效.
Template.carousel.rendered = function() {Meteor.setTimeout(function() {$('#myCarousel .carousel-indicators li:first').addClass('active');$('#myCarousel .item:first').addClass('active');}, 150);}
为什么会发生这种情况,有没有更好的解决方案?
[更新]现在我使用一个简单的 isFirst 助手来实现它.我认为这是一个更好的解决方案.
{{#each carousels}}<div class="item {{isFirst _id}}"><a href="{{link}}"><img src="{{src}}" ></a><;/div>{{/每个}}Template.carousel.isFirst = function(id) {返回 Carousels.find().fetch()[0]._id == id ?'积极的' : '';}
对于计数器,我只是让counter"从1开始,HTML如下:
<li class="active" data-target="#myCarousel" data-slide-to="0"></li>{{#每个计数器}}<li data-target="#myCarousel" data-slide-to="{{this}}"></li>{{/每个}}</ol>
Template.carousel.rendered 只在 Blaze(流星的新渲染引擎),但它曾经在 Spark(以前的版本)中运行多次.这种旧行为有效,因为它在您的 {{#each}} 块被渲染之前和之后运行.
这里的问题是 Template.carousel.rendered 在你的 {{#each}} 块被渲染之前运行,所以这些项目还不存在.
推荐模式是将{{#each}} 的内容在一个单独的模板中,然后点击那个模板的渲染事件.
顺便说一下,不再需要 Meteor.defer.
Before 0.8.0, the following code works perfectly.
<template name="carousel">
<!--Here I used the carousel of Bootstrap-->
<div id="myCarousel" class="carousel">
<ol class="carousel-indicators">
{{#each counter}}
<li data-target="#myCarousel" data-slide-to="{{this}}"></li>
{{/each}}
</ol>
<div class="carousel-inner">
{{#each carousels}}
<div class="item"><a href="{{link}}"><img src="{{src}}" ></a></div>
{{/each}}
</div>
<a class="carousel-control left" href="#myCarousel" data-slide="prev">‹</a>
<a class="carousel-control right" href="#myCarousel" data-slide="next">›</a>
</div>
</template>
Template.carousel.helpers({
carousels: function() {
return Carousels.find();
},
counter: function() {
return _.range(0, Carousels.find().count());
}
});
Template.carousel.rendered = function() {
Meteor.defer(function() {
$('#myCarousel .carousel-indicators li:first').addClass('active');
$('#myCarousel .item:first').addClass('active');
});
}
But after updating to 0.8.0, adding 'active' class doesn't work any more. Using Meteor.setTimeout instead of Meteor.defer, I finally find that it works only when the delay is long enough (sometimes longer than 150ms).
Template.carousel.rendered = function() {
Meteor.setTimeout(function() {
$('#myCarousel .carousel-indicators li:first').addClass('active');
$('#myCarousel .item:first').addClass('active');
}, 150);
}
Why does this happen, and is there any better solution?
[Updated] Now I use a simple isFirst helper to realize it. I think this is a better solution.
{{#each carousels}}
<div class="item {{isFirst _id}}"><a href="{{link}}"><img src="{{src}}" ></a></div>
{{/each}}
Template.carousel.isFirst = function(id) {
return Carousels.find().fetch()[0]._id == id ? 'active' : '';
}
As for the counter, I just make "counter" begin from 1, and the HTML is as follows:
<ol class="carousel-indicators">
<li class="active" data-target="#myCarousel" data-slide-to="0"></li>
{{#each counter}}
<li data-target="#myCarousel" data-slide-to="{{this}}"></li>
{{/each}}
</ol>
Template.carousel.rendered only runs once in Blaze (Meteor's new rendering engine), but it used to run multiple times in Spark (previous versions). This old behaviour worked because it ran before and after your {{#each}} block was rendered.
The problem here is that Template.carousel.rendered runs before your {{#each}} block is rendered, so those items don't exist yet.
The recommended pattern is to put the contents of your {{#each}} in a separate template and tap into the rendered event of that template.
By the way, Meteor.defer is no longer required.
这篇关于Meteor 0.8.0 - 无法在渲染回调中操作 DOM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!