tarkasha,
клик по блоку старт/стоп анимации, количество повторений цикла можно задать, параметр iteration, например 1 раз new Sprite(element, 1000, 1);.
<!DOCTYPE html>
<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
<style type="text/css">
.sprite {
width: 150px;
height: 150px;
overflow: hidden;
position: relative;
}
.sprite img{
opacity: 0;
position: absolute;
}
.sprite img.show{
opacity: 1;
}
</style>
<script>
class Sprite {
constructor(element, speed, iteration) {
this.root = element;
this.children = [...element.children];
this.index = 0;
this.speed = speed;
this.iteration = iteration;
this.lastTime = performance.now();
this.children[this.index].classList.add("show");
this.timer = requestAnimationFrame(this.loop.bind(this));
this.root[Symbol.for("sprite")] = this
}
loop(){
let dt = performance.now() - this.lastTime;
if(dt > this.speed){
this.lastTime = performance.now();
this.children[this.index].classList.remove("show");
this.index++;
this.index %= this.children.length;
if(typeof this.iteration == "number") {
this.index || this.iteration--;
if(this.iteration <= 0) return
}
this.children[this.index].classList.add("show");
}
this.timer = requestAnimationFrame(this.loop.bind(this));
}
toggle(){
this.timer = typeof this.timer == "number" ? (cancelAnimationFrame(this.timer), void 0) :
(
this.lastTime = performance.now(),
requestAnimationFrame(this.loop.bind(this)));
}
}
document.addEventListener("DOMContentLoaded", function(){
for(const element of document.querySelectorAll(".sprite")) {
const html = Array.from({length : 8}, (v, k) => `<img src="https://via.placeholder.com/150/FF0000/FFFFFF?text=${++k}">`);
element.insertAdjacentHTML('beforeEnd', html.join(''));
new Sprite(element, 1000);
element.addEventListener('click', ()=> element[Symbol.for("sprite")].toggle())
}
})
</script>
</head>
<body>
<div class="sprite"></div>
<div class="sprite"></div>
</body>
</html>