加载生成内容中的图像时触发事件

Fire event when images in generated content are loaded

我对某些 Javascript 生成的内容有疑问:

我使用 html 页面的 onload() 事件从服务器加载 HTML 代码并将其注入页面。因为它已经是 html 我使用我想要填充内容的节点的 innerHtml 属性。

注入 HTML 后,我调用了一个手工制作的 adjustHeights() 函数,该函数对我以这种方式创建的元素的高度进行标准化,使它们都与最高元素的高度相匹配。

除非 innerHtml 中的代码包含某种需要时间加载的图像或其他媒体(尤其是视频),否则所有这一切都完美无缺,因为 adjustHeights() 在代码注入之间被调用和 image/video/etc.

的加载时间结束

有什么方法可以在调用 adjustHeights() 之前等待所有元素加载完毕?我已经尝试过 document.onreadystatechange 属性 但是当我开始注入代码时状态已经是 'completed'。

如果可能的话,我宁愿不在 adjustHeights() 上使用基于时间的调用。

为了更清楚这里有一个例子:

var mylist = document.getElementById('mycontent');
var li;
for (var i = 0; i < res.length; i++)
{
    li = document.create('li');
    li.innerHTML=res[i];
    mylist.appendChild(li);
}
adjustHeights();

对于图像和其他类型的媒体,您应该使用 "onload" 事件,以便之后调用调整高度。 示例:

<img src="someimage.png" onload="loadImage()" >

<script>
   function loadImage() {
     // code to adjust heights
    }
</script>

这里是标准版:

var img = document.querySelector('img')

function loaded() {
  alert('loaded');
  // do something to adjust height
}

if (img.complete) {
  loaded()
} else {
  img.addEventListener('load', loaded)
  img.addEventListener('error', function() {
      alert('error')
  })
}

要在不向所有 images/videos/etc 添加内联 onload 属性的情况下执行此操作,您将必须观察 DOM 的更改。然后在每次更改时,您必须获取所有新媒体并从回调中向它们添加 onload 事件。为了防止每次都检查每个元素,一旦它们被加载,您可以通过添加 data-loaded="true" 属性 来标记它们。


观察 DOM 变化的跨浏览器解决方案可以在这个答案中找到:Detect changes in the DOM。我不会在这里重复它(但它包含在下面的演示中)。


注意:我以图像为例,但这也适用于视频和其他媒体。

在每次 DOM 更改时,首先通过检查 element.complete.如果是,触发回调函数并向其添加属性。

如果 .complete 不是这种情况,请向它们添加一个 onload 事件,该事件也会在加载后触发回调。

// Observe the DOM for changes
observeDOM(document.body, function(){ 
    checkNewMedia();
});

// Loop through all new media, add the event
var checkNewMedia = function() {

    // extend this by using document.querySelectorAll("img:not([data-loaded), video:not([data-loaded])") etc.
    var media = document.querySelectorAll('img:not([data-loaded]');
    for(var i = 0; i < media.length; i++) {
        addMediaLoadedEvent(media[i]);   
    }
}

// Fire the callback if complete, otherwise bind to onload
var addMediaLoadedEvent = function(element) {
    if (element.complete) {
        onMediaLoaded(element);
    } else {
        element.addEventListener('load', function(event) {
            onMediaLoaded(event.target);   
        });
    }
}

// The callback that is fired once an element is loaded
var onMediaLoaded = function(element) {
    element.setAttribute('data-loaded', 'true');

    adjustHeights(); // <-- your function
}

演示:fire event on each image load


如果您只想在加载 所有 图像后触发事件,您可以添加一个额外的检查来计算仍有多少图像未加载:

// The callback that is fired once an image is loaded
var onMediaLoaded = function(element) {
    element.setAttribute('data-loaded', 'true');

    // only fire when there are no media elements without the 'data-loaded' attribute left
    // again, can be extended to use video, etc.
    if(document.querySelectorAll('img:not([data-loaded])').length === 0) {
        adjustHeights(); // <-- your function
    }
}

演示:fire event on all images loaded