JavaScript-图像加载功能中的对象上设置属性,属性未设置一次外部功能
-
04-10-2019 - |
题
有时,JavaScript对我没有意义,请考虑以下代码,该代码基于X/Y瓷砖生成照片。下载每个马赛克图像后,我试图将.done属性设置为True,但是由于某种原因,这总是错误的,我在做什么错?
var tileData = [];
function generate()
{
var image = new Image();
image.onload = function()
{
// Build up the 'tileData' array with tile objects from this Image
for (var i = 0; i < tileData.length; i++)
{
var tile = tileData[i];
var tileImage = new Image();
tileImage.onload = function()
{
// Do something with this tile Image
tile.Done = true;
};
tileImage.src = tile.ImageUrl;
}
};
image.src = 'Penguins.jpg';
tryDisplayMosaic();
}
function tryDisplayMosaic()
{
setTimeout(function()
{
for (var i = 0; i < tileData.length; i++)
{
var tile = tileData[i];
if (!tile.Done)
{
tryDisplayMosaic();
return;
}
}
// If we get here then all the tiles have been downloaded
alert('All images downloaded');
}, 2000);
}
现在出于某种原因 .Done
在 tile
即使对象明确将其设置为true内部 tileImage.onload = function()
. 。我可以确保您确实被调用,因为我已经放置了 alert()
在里面打电话。现在,它只是卡在无限循环中 tryDisplayMosaic()
不断地。
另外,如果我在之前放置循环 tryDisplayMosaic()
被称为,在那个循环中我设置 .Done = true
, , 然后 .Done
财产为真, alert('All images downloaded');
会被打电话。
解决方案
顶部循环中的变量“瓷砖”都由您创建的每个“ Onload”函数共享;换句话说,相同的单个变量。尝试一下,给每个人自己的变量:
tileImage.onload = (function(myTile) {
return function()
{
// Do something with this tile Image
myTile.Done = true;
};
})(tile);
为什么这样?因为与C或Java不同,请在循环中宣布“瓷砖”。 不是 使其范围范围内的循环主体的声明块。唯一在JavaScript中为您提供范围的是功能主体。
其他提示
我看到的是您在循环内部创建关闭,这就是 一个普遍的错误. 。为了避免这种情况,您可以在循环外部创建一个更一般的封闭,该循环外部处理所有负载事件并在加载所有图像后执行功能:
// This array must be filled somewhere...
var tileData = [];
var ImageLoader = function(){
var numOfImages = 0;
var numLoaded = 0;
var callBack = function(){};
function imageLoaded(){
numLoaded++;
if(numLoaded===numOfImages){
// All images are loaded, now call the callback function
callBack.call(this);
}
}
function init(numberOfImages, fn){
numOfImages = numberOfImages;
callBack = fn;
}
return {
imageLoaded: imageLoaded,
init: init
};
}();
function tryDisplayMosaic(){
alert('All images downloaded');
}
function generate(){
// (1) Set the number of images that are to be loaded and (all tiles + penguin)
// (2) Set the function that must be called after all images are loaded
ImageLoader.init(tileData.length+1, tryDisplayMosaic);
// Load this Penguins image
var image = new Image();
image.src = 'Penguins.jpg';
image.onload = ImageLoader.imageLoaded;
// Go through each image and load it
for (var i=0; i<tileData.length; i++) {
image = new Image();
image.src = tileData[i].ImageUrl;
image.onload = ImageLoader.imageLoaded;
}
}
该代码与您的代码完全不同,但在我看来,它更漂亮。它要求您设置需要加载的图像数量,并在加载所有图像后必须执行的函数。
注意:我没有测试,我不确定 .call(this)
部分,如果论坛不正确,该论坛可能会有所帮助。
我已经测试了我的代码,它可以正常工作。此外,我已经对其进行了改进 tileData
数组,看 Jsbin 对于工作示例。