#javascript #html #animation
#javascript #HTML #Анимация
Вопрос:
CodePen
Правила:
- Каждый щелчок добавит
<progress>
элемент. - Каждый индикатор выполнения будет анимирован полностью.
- Анимации не начнутся, пока не завершится предыдущий.
Проблема:
Если вы быстро нажмете, это оживит только последнюю progress
строку. И анимации должны происходить одна за другой до завершения.
Вопрос:
Почему при быстром нажатии анимация выходит из строя?
HTML:
<div class="container">
<div class="add-progress-container">
<input class="input-seconds" type="number" min="1" max="10" value="1">
<button class="add-progress">Add progress</button>
</div>
<div class="progress-container"></div>
</div>
JS:
const container = document.querySelector('.progress-container');
const inputSeconds = document.querySelector('.input-seconds');
const addBtn = document.querySelector('.add-progress');
let animating = false;
function animateProgress(duration, el) {
const intervalId = setInterval(() => {
if(el.value >= el.max) {
animating = false;
window.clearInterval(intervalId);
console.log('finished');
checkQueue();
return;
}
el.value = el.max/duration;
}, 1000);
}
function getSeconds() {
return parseInt(inputSeconds.value, 10);
}
let progressCount = 0;
function createProgress() {
const template = `<progress data-progress="${progressCount}" value="0" max="100"></progress>`;
container.innerHTML = template;
const el = document.querySelector(`[data-progress="${progressCount}"]`);
progressCount ;
return el;
}
let queue = [];
function addProgress() {
const el = createProgress()
queue.push(el);
checkQueue();
}
function checkQueue() {
if(queue.length amp;amp; !animating) {
animating = true;
animateProgress(getSeconds(), queue.shift());
}
}
addBtn.addEventListener('click', addProgress);
Комментарии:
1. Как, по-вашему, это должно быть? Анимированный один за другим независимо от того, был ли он быстро нажат?
2. Да, один за другим, даже при быстром нажатии
3. ПРИМЕЧАНИЕ: в вашем селекторе отсутствует закрывающая квадратная скобка.
4. @trincot хороший вызов, но не то, что его нарушало:(
Ответ №1:
innerHTML =
Присвоение воссоздаст все предыдущие элементы внутри элемента container, что означает, что ваши ссылки на другие progress
элементы больше не относятся к фактическим элементам, которые создает это присвоение.
Вы должны добавить новый элемент прогресса, подобный этому:
function createProgress() {
const el = document.createElement("progress");
el.setAttribute("data-progress", progressCount);
el.setAttribute("value", 0);
el.setAttribute("max", 100);
container.appendChild(el);
return el;
}
Как прокомментировал Makyuu ниже, количество шагов для отдельных элементов прогресса выполняется только при запуске их анимации. Это означает, что если вы измените входное значение, оно будет применяться также к ранее созданным элементам (когда они еще не начали анимироваться).
Если предполагается использовать количество шагов, указанное в момент создания элемента, то измените две строки в своем коде:
queue.push([getSeconds(), el]);
и:
animateProgress(...queue.shift());
Комментарии:
1. @MatthewHarwood Не уверен, в курсе вы или нет. Но после того, как вы поставите их в очередь, вы заметите, что увеличение строки прогресса было основано на текущем значении, а не на момент его ввода.
2. В случае, если такое поведение не было предусмотрено, см. Дополнение к моему ответу.