仅在完全解码后才显示图像不起作用

Sel*_*lbi 7 javascript

我正在 Chromium 中运行 Raspberry Pi 3,用于自定义 Spotify 界面,该界面显示当前播放的歌曲。虽然这本身有效,但一首歌曲到另一首歌曲之间的过渡非常断断续续,我只是不知道该做什么了。应该发生的是图像和背景在图像完全加载之前不会淡入,因为它不应该被切成两半。

但正如你在这里看到的,情况并非如此(它只显示了几帧,但你可以清楚地看到它是如何首先只显示五分之一的封面艺术然后跳转到完整图像的):https://i .imgur.com/pQsQ26r.mp4

作为参考,这应该是这样的:https : //i.imgur.com/QWY1J38.gif

在普通 PC 上,这已经非常流畅,但我认为 RP3 太慢而无法及时解码。所以,自然地,我以为我的问题会这样解决,但结果仍然是你在第一个视频中看到的:

function changeImage(newImage) {
    var preloadImg = new Image();
    preloadImg.src = newImage;
    preloadImg.decode().then(() => {
        let artworkUrl = makeUrl(preloadImg.src);
        document.getElementById("artwork-img").style.backgroundImage = artworkUrl;
        document.getElementById("background-img").style.backgroundImage = artworkUrl;
        setArtworkOpacity("1");
    });
    setArtworkOpacity("0");
}

function setArtworkOpacity(value) {
    // the smooth fade itself is done via CSS "transition: opacity 1s;"
    document.getElementById("artwork-img").style.opacity = value;
    document.getElementById("background-img").style.opacity = value;
}
Run Code Online (Sandbox Code Playgroud)

我也试过img.onload,结果一样。

这是错误的方法吗?理想情况下,会有一个函数“在图像完全绘制之前不执行”,在这种情况下setArtworkOpacity("1"),我会将其移动到其回调中,但我找不到类似的东西。

Pie*_*ton 2

如果我仍然可以回答这个问题...您说您尝试使用 img.onload 但没有显示您的实现。

我经常使用这个,非常有效,所以看看吧。它基本上依赖于具有 HTML 属性绑定的 css。

const image = document.querySelector(".image");

function setLoaded(e) {
  e.target.setAttribute('loaded', true);
}

image.addEventListener("load", setLoaded);

setTimeout(() => {
  image.removeAttribute("loaded");
  image.setAttribute("src", "https://source.unsplash.com/1600x900/?test");
}, 2000);
Run Code Online (Sandbox Code Playgroud)
html,
body {
  margin: 0;
}

.image {
  opacity: 0;
  transition: opacity 0.3s ease;
  width: 100vw;
  height: 100vh;
  object-fit: cover;
}

.image[loaded] {
  opacity: 1;
}
Run Code Online (Sandbox Code Playgroud)
<img src="https://source.unsplash.com/random" class="image" alt="some image" />
Run Code Online (Sandbox Code Playgroud)

编辑:

为了确保我足够清楚,这里有一个更完整的答案。

我可以看到您依赖于backgroundImage显示您的数据。但是 css 中的背景图像的问题是它的反应方式与正确的 img 标签不同。您可以使用Image构造函数,但是一旦您最终仅将 url 放入 css 属性中,您就失去了它的所有好处。由于您只传递了newImageurl,因此所有 javascript 图像处理都消失了并且白费了。css 正在读取 url 并尝试尽快显示您的图像,此时没有任何 Js 技巧可以拯救您,并且它会产生您非常讨厌的小故障。

只需使用默认的 HTML 标签并在各自的属性中img添加您的url ,您就可以省去很多麻烦。 通过使用适当的语义标签而不是简单的 div 背景图像,您还将获得一些可访问性。newImagesrc

请考虑下面使用changeImage函数的代码:您可以看到loaded在 css 中使用布尔值来处理转换,而不使用 JS。

// get your elements ref in here
const images = document.querySelectorAll("img");

function setLoaded(e) {
  e.target.setAttribute('loaded', true);
  // check the CSS now
}

images.forEach(image => {
  image.addEventListener("load", setLoaded);
});

function changeImage(newImage) {
  const background = document.querySelector(".background");
  const cover = document.querySelector(".cover");

  background.removeAttribute("loaded");
  cover.removeAttribute("loaded");

  background.setAttribute("src", newImage);
  cover.setAttribute("src", newImage);
}

setTimeout(() => {
  changeImage("https://source.unsplash.com/1600x900/");
}, 2000);

setTimeout(() => {
  changeImage("https://source.unsplash.com/1920x1080/");
}, 4000);
Run Code Online (Sandbox Code Playgroud)
html,
body {
  margin: 0;
}

.header {
  position: relative;
  padding-top: 240px;
  background: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
  display: flex;
  justify-content: center;
}

img {
  opacity: 0;
  transition: opacity .5s ease;
}


/* Here's where the loaded boolean does its magic */

img[loaded] {
  opacity: 1;
}

.background {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -1;
}

.cover {
  width: 120px;
  height: 120px;
  box-shadow: 0 8px 16px rgb(33 33 33 / 50%);
  object-fit: cover;
}
Run Code Online (Sandbox Code Playgroud)
<header class="header">
  <img src="https://source.unsplash.com/random" class="background" />
  <img src="https://source.unsplash.com/random" class="cover" />
</header>
Run Code Online (Sandbox Code Playgroud)