javascriptjquery-animatestep

Javascript List Item Animations


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...

Animation I want

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.


Solution

  • 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