Javascript 图片加载在 Firefox 上失败,Chrome

Javascript image onload fails on Firefox and Chrome

我正在尝试加载带有淡入淡出效果的图像,该效果将在图像加载后触发。我注意到 onload 在 Chrome 中可以正常工作,但在 Firefox 或 Safari 中它会在图像呈现前几百毫秒被调用,因此任何低于该持续时间的动画都将被跳过。

我一直在阅读其他问题,如:

在这里,我创建了一个片段来演示使用 Picsum 大图像 —3000 x 3000— 的问题。当在 Chrome 和 运行 上打开这个问题时,图像在加载时褪色;但是当在 Firefox 或 Safari 上打开同样的问题时,图像呈现时没有淡入。

const imgElement = new Image();
const rootElement = document.getElementById("root");

rootElement.append(imgElement);
imgElement.className = "image";
imgElement.src = "https://picsum.photos/3000/3000";

imgElement.onload = function () {
  imgElement.classList.add("loaded");
};
.image {
  border: 2px solid gray;
  max-width: 100%;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.image.loaded {
  opacity: 1;
}
<div id="root"></div>

欢迎提出任何想法!

理想情况下,

  1. 您应该等待 window.load 事件,然后再将图像标签附加到 DOM
  2. onload imgElement 的处理程序应该在 imgElement 加载或附加到 DOM
  3. 之前设置

通过这些更改并将动画持续时间从 0.3 秒变为 3 秒(以便于观察),行为在浏览器中是一致的。

window.addEventListener("load", () => {
  const imgElement = new Image();
  const rootElement = document.getElementById("root");

  imgElement.onload = function () {
    imgElement.classList.add("loaded");
  };

  rootElement.append(imgElement);
  imgElement.className = "image";
  imgElement.src = "https://picsum.photos/3000/3000";
});
.image {
  border: 2px solid gray;
  max-width: 100%;
  opacity: 0;
  transition: opacity 3s ease;
}

.image.loaded {
  opacity: 1;
}
<div id="root"></div>

是的,加载事件确实对应于获取网络资源以及浏览器确保能够毫无问题地读取它的时间。
根据规范,那是 Firefox 和 Safari 触发事件的时间。
Chrome 目前在触发此事件之前会做更多的工作,因为他们会等到完全解码完成。

正如您猜对的那样,Safari 和 Firefox 将首先呈现 <img> 元素为空,在该空图像上应用过渡,然后仅呈现最终图像。

要解决此问题,您可以使用 HTML 规范中相对较新的补充:HTMLImageElement#decode()。此方法将 return 一个 Promise,在解码部分完全完成时解析。

const imgElement = new Image();
const rootElement = document.getElementById("root");

rootElement.append(imgElement);
imgElement.className = "image";
imgElement.src = "https://picsum.photos/3000/3000";

imgElement.decode().then(()=>{
  imgElement.classList.add("loaded");
});
.image {
  border: 2px solid gray;
  max-width: 100%;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.image.loaded {
  opacity: 1;
}
<div id="root"></div>

Ps:对于那些需要支持尚未支持 decode() 的旧浏览器的用户,.