Как заставить данные API сначала загрузить анимацию загрузки, прежде чем все данные будут возвращены, а затем открыть всплывающее окно после того, как API передаст все данные? Потому что в настоящее время, когда загрузка исчезает, данные во всплывающем окне не были полностью загружены, что приведет к тому, что пользователь увидит момент, когда данные будут загружены, и размер всплывающего окна изменится. Я надеюсь, что анимация загрузки будет отображаться до того, как все данные будут загружены во всплывающее окно. После загрузки данных откройте всплывающее окно и закройте анимацию загрузки. Как мне изменить это, чтобы улучшить мой пользовательский опыт? Спасибо
let btn = document.querySelector('.btn');
let popup = document.querySelector('.popup');
let wrap = document.querySelector('.wrap');
let photo = document.querySelector('.photo');
let svg = document.querySelector('svg');
btn.addEventListener('click', function(e) {
svg.style.display = "block"
axios.get("https://dog.ceo/api/breeds/image/random")
.then((response) => {
let Data = response.data.message;
photo.src = Data;
svg.style.display = "none"
popup.style.display = "flex";
})
.catch((error) => console.info(error));
});
wrap.addEventListener('click', function(e) {
e.stopPropagation();
});
popup.addEventListener('click', function() {
popup.style.display = "none";
});.popup {
background-color: rgba(0, 0, 0, 0.5);
width: 100%;
height: 100vh;
display: none;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.popup .wrap {
width: 300px;
background-color: #fff;
text-align: center;
border-radius: 20px;
padding: 20px;
}
.popup .wrap .photo {
width: 100%;
height: 100%;
object-fit: conver;
border-radius: 20px;
}
svg {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
svg .load {
stroke-dasharray: 0 500;
animation: rot 1s linear infinite;
}
@keyframes rot {
100% {
stroke-dasharray: 500 500;
}
}<script src = "https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.2/axios.min.js"></script>
<button class='btn'>open data</button>
<div class = "popup">
<div class = "wrap">
<h1>Pet</h1>
<img class = "photo" src = "" alt = "">
</div>
</div>
<svg width = "240px" height = "240px" version = "1.1" xmlns = "http://www.w3.org/2000/svg">
<circle cx = "110" cy = "110" r = "90" stroke-width = "10" stroke = "gainsboro" fill = "none"></circle>
<circle cx = "110" cy = "110" r = "90" stroke-width = "10" stroke = "darkturquoise" fill = "none" class = "load"></circle>
</svg>


![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Ваш код выглядит хорошо, но вам не хватает одной маленькой детали. Сложность заключается в том, что загрузка изображения также требует времени, и вы хотите показывать индикатор загрузки во время загрузки самого изображения.
Исходя из вышеизложенного, нужно дождаться полной загрузки изображения и только потом показывать окончательный вид.
Вот изменение, которое вам нужно сделать:
btn.addEventListener('click', function(e) {
svg.style.display = "block"
axios.get("https://dog.ceo/api/breeds/image/random")
.then((response) => {
// set handler to show the image once it is loaded
photo.addEventListener('load', () => {
svg.style.display = "none"
popup.style.display = "flex";
});
// set image src after adding 'load' handler
photo.src = response.data.message;
})
.catch((error) => console.info(error));
});
Обновление на основе дополнительных вопросов в комментариях
Для обработки нескольких изображений вам понадобится немного более сложный подход. Поскольку ваш код был просто примером для одного изображения, для простоты и демонстрации, основываясь на вашем вопросе в комментариях, я предполагаю, что ваш сервер может возвращать массив URL-адресов изображений.
btn.addEventListener('click', function(e) {
svg.style.display = "block"
axios.get("https://dog.ceo/api/breeds/image/random")
.then((response) => {
// assuming your API returns tens of images
// this is an array of image URLs
const imageURLs = response.message.imageURLs;
// retrieving array of img elements from the page
// I would recommend actually generating img tags here
const imageElements = document.querySelector('.photo');
// we create a Promise for each img element
const imagePromises = imageElements.map((element, index) => {
return new Promise((resolve, reject) => {
element.addEventHandler('load', resolve);
element.addEventHandler('error', (e) => reject(e));
element.src = imageURLs[index];
});
});
// this will wait for all the promises to settle
Promise.allSettled(imagePromises).then((results) => {
// go through 'results' and handle errors if needed
// otherwise, this is the place where you know that
// all the images are loaded/failed
svg.style.display = "none"
popup.style.display = "flex";
});
})
.catch((error) => console.info(error));
});
Что касается того, что вы должны делать в catch, это во многом зависит от поведения и визуальной обратной связи, которую вы должны сделать в случае ошибок.
Если вы хотите уведомить пользователя об ошибке, вы можете использовать функцию catch, например, для отображения какого-либо всплывающего окна.
Пожалуйста, дайте мне знать, если это поможет.
Спасибо за ответ, но я что-то не понимаю! Вы хотите контролировать, хотите ли вы открыть всплывающее окно, когда все изображения загружены? Потому что этот пример — простой пример, написанный для того, чтобы задать этот вопрос. Если в моём попапе сегодня не одно фото, а десятки полей, которые присылает бэкенд, то перед открытием попапа тоже надо следить, каждое ли поле загружено? Спасибо.
Также задайте вопрос, потому что я не знаком с использованием javaScript, хотел бы спросить! Какую информацию обычно следует помещать в улов? Насколько я понимаю, это просто возвращает сообщение об ошибке. Если сегодня нет необходимости возвращать пользователю сообщение об ошибке, то обычно не нужно ничего писать в catch?
@WEIA Я обновил ответ, добавив обработку нескольких изображений. Дайте мне знать, если у вас возникнут дополнительные вопросы.
Чтобы решить эту проблему, вы можете попробовать добавить свойство onload к переменной photo. Событие onload происходит, когда объект загружен. Ссылка: https://www.w3schools.com/jsref/event_onload.asp
let btn = document.querySelector('.btn');
let popup = document.querySelector('.popup');
let wrap = document.querySelector('.wrap');
let photo = document.querySelector('.photo');
let svg = document.querySelector('svg');
btn.addEventListener('click', function(e) {
svg.style.display = "block"
axios.get("https://dog.ceo/api/breeds/image/random")
.then((response) => {
let Data = response.data.message;
photo.src = Data;
photo.onload = () => {
svg.style.display = "none";
popup.style.display = "flex";
}
})
.catch((error) => console.info(error));
});
wrap.addEventListener('click', function(e) {
e.stopPropagation();
});
popup.addEventListener('click', function() {
popup.style.display = "none";
});.popup {
background-color: rgba(0, 0, 0, 0.5);
width: 100%;
height: 100vh;
display: none;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.popup .wrap {
width: 300px;
background-color: #fff;
text-align: center;
border-radius: 20px;
padding: 20px;
}
.popup .wrap .photo {
width: 100%;
height: 100%;
object-fit: conver;
border-radius: 20px;
}
svg {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
svg .load {
stroke-dasharray: 0 500;
animation: rot 1s linear infinite;
}
@keyframes rot {
100% {
stroke-dasharray: 500 500;
}
}<script src = "https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.2/axios.min.js"></script>
<button class='btn'>open data</button>
<div class = "popup">
<div class = "wrap">
<h1>Pet</h1>
<img class = "photo" src = "" alt = "">
</div>
</div>
<svg width = "240px" height = "240px" version = "1.1" xmlns = "http://www.w3.org/2000/svg">
<circle cx = "110" cy = "110" r = "90" stroke-width = "10" stroke = "gainsboro" fill = "none"></circle>
<circle cx = "110" cy = "110" r = "90" stroke-width = "10" stroke = "darkturquoise" fill = "none" class = "load"></circle>
</svg>