我在Chromium中运行Raspberry Pi 3,用于显示当前播放的歌曲的自定义Spotify界面。虽然这本身是有效的,但一首歌与另一首歌之间的过渡非常不稳定,我只是不知道该怎么做了。应该发生的是,在图像完全加载之前,图像和背景不会淡出,也就是说,它不应该被切成两半。
但正如你在这里看到的,情况并非如此(它只显示了几帧,但你可以清楚地看到它是如何首先只显示五分之一的封面,然后跳转到完整的图像):https://i.imgur.com/pQsQ26r.mp4
作为参考,应该是这样的:https://i.stack.imgur.com/MPICj.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;
}
我也试过img.onload
,结果相同。
这是错误的方法吗?理想情况下,会有一个函数去"不执行,直到图像已完全绘制";在这种情况下,我将setArtworkOpacity("1")
移动到它的回调中,但我找不到这样的东西。
如果我还可以回答这个…你说你试过了。Onload,但没有显示你的实现
我经常使用这个,它非常有效,所以看看它。它基本上依赖于css和HTML属性绑定。
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);
html,
body {
margin: 0;
}
.image {
opacity: 0;
transition: opacity 0.3s ease;
width: 100vw;
height: 100vh;
object-fit: cover;
}
.image[loaded] {
opacity: 1;
}
<img src="https://source.unsplash.com/random" class="image" alt="some image" />
编辑:
为了确保我足够清楚,这里有一个更完整的答案。
我可以看到你依靠backgroundImage
来显示你的数据。但是css中背景图像的反应方式与正常的img标签不同。您使用了Image
构造函数,但是当您最终只将url放在css属性中时,您就失去了它的所有好处。由于您只传递newImage
url,所以所有的javascript图像处理都消失了,并且没有做任何事情. css正在读取url并尝试尽可能快地显示你的图像,没有Js技巧可以在这一点上拯救你,它会产生你讨厌的小故障。
您可以通过简单地使用默认的HTMLimg
标签并在各自的src
属性中添加您的newImage
url来节省很多麻烦。您还可以通过使用适当的语义标记而不是简单的div背景图像来获得一点可访问性。
请考虑下面使用changeImage
函数的代码:你可以看到在css中使用loaded
布尔值来处理转换,而不使用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);
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;
}
<header class="header">
<img src="https://source.unsplash.com/random" class="background" />
<img src="https://source.unsplash.com/random" class="cover" />
</header>
window.addEventListener("load", event => {
var img = document.querySelector('img');
var isLoaded = img.complete && img.naturalHeight !== 0;
alert(isLoaded); //do what you want to do after artwork image loaded
});
尝试使用WebP图像(.webp
)。