Reputation: 127
I am working on a very basic animation where classes are removed from list items once they have been loaded and appended to the document. The issue I am having is with the animation itself. I want the animation to execute in a stepped manner like the image below...
What actually though is that the loop runs completely, console.log messages get output in a stepped manner, but the classes are all removed at the same time once the loop has completed. How can I change this behavior? Why would the console.log messages be stepped but the classList.remove functionality is not executed at the same time?
Here is my code...
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
/**/
function showListItems() {
var listItems = document.querySelector('.idList');
var n = 20;
var c = 0;
var itemArray = new Array();
for (var i = 0; i < listItems.children.length; i++) {
var item = listItems.children[i];
if (item.classList && item.classList.contains('idList__item--hide')) {
console.log('Item: ', item);
itemArray[c] = item;
c++;
}
}
console.log('Item Array: ', itemArray);
itemArray.forEach(function(el, index) {
sleep(n);
el.classList.remove('idList__item--hide');
console.log("EL[" + index + "]: ", el);
});
}
I realize this code may look over complex and perhaps it is, but I have tried about everything I can think of. I have tried using promises, for loops, now the forEach method.
Thank you.
Upvotes: 0
Views: 1040
Reputation: 3618
The browser doesn't update until javascript finishes running. Your script doesn't relinquished control back to the browser while sleeping so the browser can't update. This is exactly what setTimeout
is for.
Change
itemArray.forEach(function(el, index) {
sleep(n);
el.classList.remove('idList__item--hide');
console.log("EL[" + index + "]: ", el);
});
to
itemArray.forEach(function(el, index) {
const ms = n * (index + 1);
setTimeout(function() {
el.classList.remove('idList__item--hide');
console.log("EL[" + index + "]: ", el);
}, ms);
});
We're scheduling all the remove
calls in advance which is why we're multiplying n
by index + 1
.
And in case you're interested, here is the code I used to test sleep
vs setTimeout
.
https://codepen.io/rockysims/pen/jeJggZ
Upvotes: 1
Reputation: 11
This may be a bad way but it should solve your problem.
You can use setTimeout() in forEach, and use index to change time parameter, like it:
itemArray.forEach(function(el, index) {
setTimeout(function(){
el.classList.remove('idList__item--hide')
},500*(index+1))
});
Upvotes: 1
Reputation: 1591
I used Jquery each and setTimeout functions for chaining the animations.
$( "li" ).each(function( index ) {
var listItem = $( this );
setTimeout(function() {
listItem.animate({
opacity: 1
}, 500);
}, (index + 1) * 500);
});
ul {
padding : 20px;
}
ul li {
list-style : none;
height : 50px;
background-color : lightgreen;
margin : 20px;
opacity : 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>Hello world 1</li>
<li>Hello world 2</li>
<li>Hello world 3</li>
<li>Hello world 4</li>
</ul>
Upvotes: 0