我创建了自己的小图片滑块,为了让加载程序正常工作,我必须创建一个addEventListener
,然后将加载的图像附加到DOM中。
然而,在这种情况下还有一个错误:当图片需要一段时间加载并且用户点击加载以查看下一张图片时,事件监听器是仍然在后台工作,当图像完全加载时,它会覆盖用户当前正在查看的内容。
我的HTML:
<template name="ImageGallery">
{{#each galleryImages}}
{{#if viewingImage}}
{{> Image}}
{{/if}}
{{/each}}
</template>
<template name="Image">
<div class="image-in-gallery">LOADING</div>
</template>
检查&#34;图像&#34;用户想要看到的是我们在each
迭代中点击的那个(从而显示它):
Template.ImageGallery.helpers({
viewingImage: function() {
var self = this
var galleryImages = Template.parentData().galleryImages
var renderImage = false
var viewing = Template.instance().viewingImage.get()
var posOfThisImage = lodash.indexOf(galleryImages, self)
if (viewing === posOfThisImage) {
renderImage = true
}
return renderImage
}
})
使用户能够看到下一个&#34;图像&#34;如果我们到达目的地就循环:
Template.ImageGallery.events({
'click .click-to-see-next-image': function(event, template) {
var viewing = template.viewingImage.get()
var imageCount = this.galleryImages.length
var nextImage = ++viewing
if (nextImage < imageCount) {
template.viewingImage.set(nextImage)
}
else {
template.viewingImage.set(0)
}
}
})
装载机:
Template.Image.onRendered({
var imageUrl = Template.currentData().name + Template.parentData().name + '.jpg'
var imageObj = new Image()
imageObj.src = imageUrl
imageObj.addEventListener('load', function() {
$('.image-in-gallery').empty()
$('.image-in-gallery').append($(imageObj))
}
})
您可以看到问题所在:empty()
和append()
当然会覆盖用户当前正在查看的图像,并将其设置为下次加载的图像。
我想在addEventListener
函数中以某种方式添加中断,以查看加载的图像是否实际上是用户想要查看的图像。但有两个问题:
1)此模板中的ReactiveVar
变量不可用。毕竟我是否需要使用Session
变量?
2)我不知道如何打破。
有人可以帮忙吗?
答案 0 :(得分:4)
阅读你的问题让我想到,也许有可能重建你的模板设置而不需要模板中的这个复杂的代码并修复根本原因 - 无法理解当前可见的图像并轻松设置下一个可见。
我发现最好的办法就是忘记尝试从子模板访问父数据上下文,因为无论如何都无法通过数据上下文访问-webkit-touch-callout: none
(正如您无疑发现的那样)。数据上下文层次结构依赖于Blaze html,因此不建议以这种方式使用它们。
另一个极端是拥有Session变量,这将是非常全局的。
幸运的是,有一个中途。在Template命名空间之外定义ReactiveVar
,然后父模板和子模板都可以同样访问它。如果您正在尝试编写包,并且不想污染全局会话命名空间,那么这种方法效果特别好。
例如将其放在hello.html中:
ReactiveVar
,这在hello.js
中<head>
<title>rangetest</title>
</head>
<body>
<h1>Welcome to RangeTest!</h1>
{{> hello}}
{{> rangeList}}
</body>
<template name="hello">
<p>And another test {{anotherTest}}</p>
</template>
<template name="rangeList">
{{#each ranges}}
{{> range}}
{{/each}}
</template>
<template name="range">
<p>{{name}}</p>
<input type="range" value="{{value}}" min="1" max="10">
</template>
你会看到反应变量在模板之间很好地传播。
可能这不会回答你关于事件监听器的问题,但希望你能够按照我提出的方式实现反应之后用if (Meteor.isClient) {
anotherDict = new ReactiveDict('another');
anotherDict.set('hey',2);
Template.hello.helpers({
anotherTest: function() {
return anotherDict.get('hey');
}
});
Template.rangeList.helpers({
ranges: function() {
var ranges = [
{
'name':'first',
'value': 5
},
{
'name':'second',
'value': 6
},
{
'name':'third',
'value': 7
},
{
'name':'fourth',
'value': 8
}
];
return ranges;
},
});
Template.range.events({
'input input[type="range"]': function(e,t) {
var value = parseInt(e.target.value);
anotherDict.set('hey',value);
}
});
}
事件监听器替换你手动添加的事件监听器,那些将是紧密的绑定到特定的子模板,他们将无法无法预测。
P.S。我有使用ReactiveDict和范围输入的示例,因为这是我需要解决类似问题的用例。我调查了所有三个选项,这是最终工作的一个选项,并且或多或少地感受到流星的方式。
答案 1 :(得分:2)
我知道,可能问题在于架构本身。
您应该使用两种不同的数据结构。将加载与渲染分开。
让我们说galleryImages是图像数据,你应该迭代它们只是为了在客户端加载图像并将它们推送到不同的数组loadedImages中。
然后模板应该迭代并与loadedImages交互。
很抱歉,但我对流星不熟悉,我无法提供代码。
答案 2 :(得分:2)
我认为您的代码存在两个缺陷:
销毁模板时,永远不会移除load
事件。因此,即使您的模板因为单击以获取下一个图像而被销毁,图像仍会在您的浏览器中加载并启动load
事件。 this destroyed elements
您在$
中使用onRendered
。 $
指的是全局DOM,而removeEventListener只会查找模板的本地DOM。如果您使用过this.$
,那么它应该会抛出错误,因为您的本地DOM已被销毁,并且不会显示错误的图像。
我就是这样做的: this.$
答案 3 :(得分:1)
使用dummy / fake / hidden img标签初始加载下一个图像,并监听此元素的load事件,在将图像加载到此元素后,它会被缓存,你可以把它放进观察者。
提示:对于伪造元素,你应该使用
.fake-img {visibility: hidden; position: absolute}
对于隐藏图片代码,如果规则为display: none
但我也同意,你应该考虑一下你的架构,尽量不要在流星中使用jquery dom操作