Your code already looks pretty clean. Good work! There are only a few things I would recommend changing.
Don't define timings in CSS that should be defined in JavaScript. In this specific case using a transition made it possible to simplify the code significantly, however in a more involved example it would become problematic. What happens if one progress bar takes 2 seconds to complete, and another takes 5?
Instead of using
getElementsByClassName('cls')[0], you can usequerySelector('.cls')for more readable code. Though this can be slower, it really isn't an issue unless it is being run thousands of times per second.There is a built in
<progress>element that you may want to use.It is a good idea to wrap template elements in a
<template>element.
Here's a simple demo that defines the timing in the JavaScript.
function Loader(element, time) {
return new Promise(resolve => {
let intervalId;
function tick() {
element.value = parseInt(element.value, 10) + 1
if (element.value == element.max) {
clearInterval(intervalId)
resolve()
}
}
setInterval(tick, time / element.max)
})
}
let promise = Promise.resolve()
let container = document.querySelector('.container')
let template = document.querySelector('template')
function addProgress() {
let progress = document.importNode(template.content, true)
container.appendChild(progress)
// progress is a document fragment, not the template element
return container.querySelector('progress:last-child')
}
document.querySelector('button').addEventListener('click', () => {
let bar = addProgress()
promise = promise.then(() => Loader(bar, 3000))
})
progress {
display: block;
width: 100%;
}
<template>
<progress max="100" value="0"></progress>
</template>
<div class="container"></div>
<button>Click me!</button>