var c=document.getElementById("cvs");
var ctx=c.getContext("2d");
var imgArray = [];
for (var i=0;i<data.length;i++){
var drawRepeat = Math.floor((data[i]/divider));
imgArray[i] = [];
for (var j=0;j<drawRepeat;j++){
//alert(j);
var xPos = ((i*30)+10);
var yPos = 250-((j*30)+30);
imgArray[i][j] = new Image();
imgArray[i][j].src="assets/orange.png";
imgArray[i][j].onload = function(){
ctx.drawImage(imgArray[i][j],xPos,yPos);
};
}
}
我想用for循环绘制多个图像。奇怪的是当我用for循环放置一个alert()时它有效吗?但如果我发表评论,它只会显示1张图片。
有没有解决方案?
答案 0 :(得分:3)
这是与闭包有关的问题。我会在给出代码后解释。
var c = document.getElementById("cvs");
var ctx = c.getContext("2d");
var imgArray = [];
for (var i = 0; i < data.length; i++) {
var drawRepeat = Math.floor((data[i] / divider));
imgArray[i] = [];
for (var j = 0; j < drawRepeat; j++) {
//alert(j);
(function (_i, _j) {
var xPos = ((_i * 30) + 10);
var yPos = 250 - ((_j * 30) + 30);
imgArray[_i][_j] = new Image();
imgArray[_i][_j].src = "assets/orange.png";
imgArray[_i][_j].onload = function () {
ctx.drawImage(imgArray[_i][_j], xPos, yPos);
};
})(i, j);
}
}
<强>更新强>:
我正在做这个奇怪的事情的原因是注册到onload
事件的函数将被异步调用 - 即循环将继续并且函数将在图像加载时被调用,而不是在那时时刻。所以会发生这样的循环,并且一旦完成(注意这可能在完成之前发生),i
的值将是data.length - 1
。现在,加载一些图像,然后调用该函数。此函数引用i
(在您提供的代码中),现在为data.length - 1
。因此,只绘制最后一张图像。我知道这很令人困惑 - 当我第一次偶然发现关闭时,我感到很困惑。我建议你阅读一些关于它们的好文章,你会看到问题所在。
我们做的是创建一个范围(专家可能会发现这个表达式存在问题),创建一个立即调用的匿名函数,并传递i
的值和j
因为它是参数 - _i
和_j
(请注意,我们可以使用相同的名称,但为了避免混淆,我没有使用相同的名称)。现在,这些是函数的本地函数,不会被更改。因此,当加载i
图像时,会调用onload函数来绘制数组中的_i
图像。
我没有很好地解释,所以正如我所说,请阅读关于闭包的一些文章。
答案 1 :(得分:0)
预加载图像,而不是使用onload处理程序。
答案 2 :(得分:0)
var c=document.getElementById("cvs");
var ctx=c.getContext("2d");
var img = new Image();
img.src="assets/orange.png";
img.onload = function(){
for (var i=0;i<data.length;i++){
var drawRepeat = Math.floor((data[i]/divider));
for (var j=0;j<drawRepeat;j++){
//alert(j);
var xPos = ((i*30)+10);
var yPos = 250-((j*30)+30);
ctx.drawImage(img,xPos,yPos);
}
}
}
我设法通过将onload放在for循环外面并将drawImage命令放在onload函数和for循环中来解决onload的问题。也适用。