JavaScript appendChild onload事件

3
我正在将动态创建的图像元素附加到文档中。
var img = new Image();
img.src = 'test.jpg',
img.onload = function() {

    var addedImg = container.appendChild(img);
    console.log(img.width); //old width.
}

这里的问题在于,如果我在container.appendChild(img)之后立即获取图像的尺寸,那么它将返回源文件的尺寸,因为appendChild还没有完成(没有重新绘制?),尺寸尚未重新计算。
var addedImg = container.appendChild(img);
console.log(img.width) //returns original width of the image

所以,我想知道是否有可能捕获appendChild的加载事件?

我知道可以使用setTimeout / setInterval,但我认为应该有更优雅的解决方案。

var addedImg = container.appendChild(img);
setTimeout(function() {
    console.log(img.width); //return correct resolution after image dimensions were recalculated
}, 1000);

setTimeout/setInterval的问题在于我不知道元素何时最终被附加和重绘。我必须在循环中运行它。
我试图监听DOMNodeInsertedIntoDocument和DOMNodeInserted事件,但是它们都无法正常工作。
img.addEventListener("DOMNodeInserted", onImageInserted, false);
img.addEventListener("DOMNodeInsertedIntoDocument", onImageInserted, false);

function onImageInserted(event) {
    console.log(img.width); //still wrong width
}

然而,它似乎是在appendChild被触发后立即运行的。
这里是fiddle链接,您可以看到我所说的: http://jsfiddle.net/0zyybmf2/ 注意:请不要建议检查父容器的宽度。我需要获取图像的宽度。 非常感谢您提供的任何帮助。

2
图片具有“load”事件。 - elclanrs
img.onload = function() {alert(this.naturalWidth)} - dandavis
这不是我想说的。这段代码已经在img.load内部了。这是关于捕获重绘事件的问题。 - Sray
1
appendChild还没有完成,什么? - Hacketo
抱歉,各位,我表述不够清楚。我更新了帖子,并提供了一个fiddle,这样你们就可以看到它的实际效果了。 - Sray
就像在你的回调函数之后立即完成重绘一样,使用setTimeout(fn..., 0)是相同的。 - Hacketo
3个回答

2

不幸的是,看起来你必须将控制权交还给浏览器(就像你使用setTimeout()一样),才能观察到最终的尺寸; 幸运的是,超时时间可以非常短。

container.appendChild(img);
setTimeout(function() {
    console.log(img.width);
}, 0);

换句话说,重绘(和布局更新)在函数返回后并在 setTimeout 触发之前完成。顺便提一下,在附加加载处理程序之后才设置 .src 属性是明智的;我曾经不得不调试我的代码几次,才意识到缓存的图像可能会在更改 .src 后立即触发加载处理程序。演示请参见:Demo

1
谢谢。但是我知道 setTimeout。我在原问题中提到了那个。setTimeout 的问题在于我不知道什么时候触发重绘。唯一可能的解决办法是在 setTimeout 内检查宽度是否更改(我认为 setInterval 对此会更好)。我想知道是否还有其他解决方案。 - Sray
@Sray 好的,你将超时值设置为1秒,这是不必要的;另外,为什么你需要知道重绘完成的确切时间?它会在你的函数完成后立即完成,这就是整个重点。 - Ja͢ck
不需要使用setTimeout。请参考我的回答。 - N K
@NK 是的,但是在你的回答中,你会在警报显示之前看到图像加载,这可能不是 OP 想要的。 - Ja͢ck
@Ja͢ck,2分。首先,在你的解决方案中,图像也是在登录到控制台之前加载的(尝试使用警报而不是确保)。其次,如果在将src设置为图像元素后订阅onload事件,它并不总是正常工作。 - N K
显示剩余3条评论

1

var img = new Image();
var container = document.getElementsByTagName("div")[0];
container.appendChild(img);

img.onload = function() {
  alert('Width = ' + img.width);
}

img.src = "https://picsum.photos/id/1015/600/400";
div {
    width: 200px;
}

img {
    display: block;
    width: 100%;
    height: 100%;
}
<div></div>


0

在2022年,MutationObserver可能是一个解决方案。

const callback = ( mutations, mutationObserver ) => {
   mutationObserver.disconnect();
   const MutationRecord = [...mutations];
   console.log( MutationRecord );
};

let mutationObserver = new MutationObserver( callback );

mutationObserver.observe( document.querySelector( "#mmp-map-2b40f571" ), { childList: true, subtree: false } );

document.querySelector( "#mmp-map-2b40f571" ).appendChild( document.createElement( "div" ) );
<div id="mmp-map-2b40f571"></div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接