как реализовать правильную анимацию загрузки и clearInterval после загрузки каждой картинки
const images = document.querySelectorAll('img');
let imageInterval;
imageInterval = setInterval(() => {
for (let i = 0; i < images.length; i++) {
if (images[i].complete) {
images[i].classList.remove('spinner');
} else {
images[i].classList.add('spinner');
}
}
}, 50);
body {
display: flex;
flex-flow: column;
}
img {
width: 100vh;
margin: 100px auto;
}
.spinner {
margin: 100px auto;
animation: loading-bar-spinner 0.50s linear infinite;
}
.spinner {
width: 40px;
height: 40px;
border: solid 4px transparent;
border-top-color: #000000;
border-left-color: #000000;
border-radius: 100%;
background: hidden;
}
@keyframes loading-bar-spinner {
0% {
transform: rotate(0deg)
}
100% {
transform: rotate(360deg);
}
}
<img src="https://images.unsplash.com/photo-1612637829340-c91db24ca338?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612694537513-b772cb21f725?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612712393889-c8ffe831ba9f?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612697433795-e2b675b15bfd?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80">
<img src="https://images.unsplash.com/photo-1612640189088-9b0fda86cad7?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80">
Как реализовать clearinterval тут только после того как все элементы будут загружены? можно сделать проверку отдельно для каждого индекса - (if images[n0].complete && images [n1].complete images[n2].complete и т.п.), но так будет не красиво, да и вдруг у меня будет массив из 200 картинок? + как сделать чтобы при воспроизведении анимации не было части загруженной картинки? Чтобы не было вот так : (как видите тут часть не загруженной картинки, а мне такое не надо) 
Ответы (3 шт):
Как реализовать clearinterval тут только после того как все элементы будут загружены?
Изначально не запускать его =) Т.к. он служит костыльным методом, чтобы поймать завершение загрузки. Для этого существует событие load.
Как сделать чтобы при воспроизведении анимации не было части загруженной картинки?
В setInterval замените 50 на 1000: проблема станет еще очевиднее. Часть загруженной картинки проскакивает из-за временного зазора между загрузкой картинки и следующим тиком интервала через 50мс.
const images = document.querySelectorAll('img');
for (let i = 0; i < images.length; i++) {
// Если картинка и так успела загрузиться, ничего не надо делать.
if (!images[i].complete) {
images[i].classList.add('spinner');
images[i].addEventListener("load", remove_loader);
}
}
function remove_loader() {
this.classList.remove('spinner');
};
img {
width: 50px;
height: 50px;
}
.spinner {
margin: 100px auto;
animation: loading-bar-spinner 0.50s linear infinite;
}
.spinner {
width: 40px;
height: 40px;
border: solid 4px transparent;
border-top-color: #000000;
border-left-color: #000000;
border-radius: 100%;
background: hidden;
}
@keyframes loading-bar-spinner {
0% {
transform: rotate(0deg)
}
100% {
transform: rotate(360deg);
}
}
<img src="https://images.unsplash.com/photo-1612637829340-c91db24ca338?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612694537513-b772cb21f725?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612712393889-c8ffe831ba9f?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612697433795-e2b675b15bfd?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80">
<img src="https://images.unsplash.com/photo-1612640189088-9b0fda86cad7?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80">
Проблема предыдущего ответа: событие load уменьшает временной зазор, но картинка всё равно мелькает до удаления loader-а. requestAnimationFrame тоже не помогает, пропускает один кадр.
«В лоб» железобетонно можно решить, если завернуть картинку во временный блок, который сам будет loader-ом, и будет через CSS скрывать внутренний img до его загрузки:
const images = document.querySelectorAll('img');
for (let i = 0; i < images.length; i++) {
if (!images[i].complete) wrap_tmp_loader(images[i]);
}
function wrap_tmp_loader(img) {
let div = document.createElement("div");
div.className = "spinner";
img.insertAdjacentElement("beforebegin", div);
// Вставка div перед текущим img
div.appendChild(img);
// appendChild не копирует элемент, а переносит (во внутрь div)
img.addEventListener("load", destroy_tmp_loader);
};
function destroy_tmp_loader() {
let img = this;
let div = this.parentNode;
div.insertAdjacentElement("afterend", img);
// Возвращает картинку туда, где она изначально была
div.parentNode.removeChild(div);
// Удаляет блок, будто ничего не было
}
img {
width: 50px;
height: 50px;
vertical-align: top;
}
.spinner {
display: inline-block;
margin: 100px auto;
animation: loading-bar-spinner 0.50s linear infinite;
width: 40px;
height: 40px;
border: solid 4px transparent;
border-top-color: #000000;
border-left-color: #000000;
border-radius: 100%;
}
.spinner > img {
/* Картинка гаратированно будет скрыта, пока находится внутри блока */
display: none;
}
@keyframes loading-bar-spinner {
0% {
transform: rotate(0deg)
}
100% {
transform: rotate(360deg);
}
}
<img src="https://images.unsplash.com/photo-1612637829340-c91db24ca338?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612694537513-b772cb21f725?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612712393889-c8ffe831ba9f?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img src="https://images.unsplash.com/photo-1612697433795-e2b675b15bfd?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80">
<img src="https://images.unsplash.com/photo-1612640189088-9b0fda86cad7?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80">
Сам задал, сам ответил, лол.
js
const images = document.querySelectorAll('img');
let imageInterval;
imageInterval = setInterval(() => {
for(let i = 0;i < images.length;i++){
if(clearIntervalFunction){
clearInterval(imageInterval);
if(images[i].complete){
images[i].classList.remove('spinner');
}else{
images[i].classList.add('spinner');
}
}
}
}, 50);
function clearIntervalFunction(elem){
return elem.complete;
}
css
.spinner{width: 0px;
height: 0px;border: solid 4px transparent;
border-top-color: #000000;
border-left-color: #000000;border-radius: 100%;
background: hidden;
padding: 20px;}
Спиннер немного не тот, т.к. не получилось добиться чистого полукруга. А в остальном всё работает.
const images = document.querySelectorAll('img');
for (let i = 0; i < images.length; i++) {
let img = images[i];
img.classList.add("loading");
let controlImage = new Image();
controlImage.src = img.getAttribute("source");
controlImage.onload = function() {
img.src = controlImage.src;
img.removeAttribute("source");
img.classList.remove("loading");
};
}
body {
display: flex;
flex-flow: column;
}
img {
width: 100vh;
}
.loading {
animation: loading-bar-spinner 0.5s linear infinite;
width: 40px;
height: 40px;
border-top: #000 solid 4px;
border-left: #000 solid 4px;
border-right: transparent solid 0px;
border-bottom: transparent solid 0px;
border-radius: 100%;
}
@keyframes loading-bar-spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<title>Document</title>
</head>
<body>
<img source="https://images.unsplash.com/photo-1612637829340-c91db24ca338?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img source="https://images.unsplash.com/photo-1612694537513-b772cb21f725?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img source="https://images.unsplash.com/photo-1612712393889-c8ffe831ba9f?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80">
<img source="https://images.unsplash.com/photo-1612697433795-e2b675b15bfd?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80">
<img source="https://images.unsplash.com/photo-1612640189088-9b0fda86cad7?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80">
</body>
</html>