skip to Main Content

I have a page and script like this:

I want to scroll to each listitem pause for a sec then scroll to next listitem and continue till the end of the list.

My attempted code looks like this:

const sleep = (time) => new Promise(res => setTimeout(res, time, "done sleeping"));


let elm = document.querySelector('#pane-side');
let listitems = elm.children[0].children[0].children
for (let index = 0; index < listitems.length; index++) {
  const y = listitems[index].getBoundingClientRect().top + window.scrollY;
  elm.scroll({
    top: y,
    behavior: 'smooth'
  });
  sleep(1000).then(msg => console.log(msg));
}
<div id="pane-side">
  <div>
    <div>
      <div>
        <div role="listitem"></div>
        <div role="listitem"></div>
        <div role="listitem"></div>
        <div role="listitem"></div>
        <div role="listitem"></div>
        <div role="listitem"></div>
        <div role="listitem"></div>
      </div>
    </div>
  </div>
</div>

It only scrolls once to the first listitem and then does nothing.

Another variant that I tries was replacing elm.scroll({..}) with listitems[index].scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" }); which didnt even scroll once.

2

Answers


  1. You need some more CSS to do this

    And why not use interval?

    Here is a version that uses your original scroll and does not move the page. I had to tweak the offsetTop to handle margins and padding

    Change the counting to

    const listItem = listitems[cnt % len];

    and add cnt++ to the end of the function to loop around

    let cnt = 0, tId;
    const elm = document.querySelector('#pane-side');
    const listitems = elm.querySelectorAll("[role=listitem]");
    const len = listitems.length;
    
    const scrollDiv = () => {
      const listItem = listitems[cnt];
      const topPosition = listItem.offsetTop-7; // adjusted for padding/margin
      elm.scroll({
        top: topPosition,
        behavior: 'smooth'
      });
      cnt++;
      // stop at the end
      if (cnt >= listitems.length) {
        clearInterval(tId);
        return; 
      }
    
    
    };
    scrollDiv(); // start
    tId = setInterval(scrollDiv, 1000)
    #pane-side {
      height: 1000px;
      overflow: scroll
    }
    
    [role=listitem] {
      height: 500px;
      background-color: red
    }
    <div id="pane-side">
      <div>
        <div>
          <div>
            <div role="listitem">1</div>
            <div role="listitem">2</div>
            <div role="listitem">3</div>
            <div role="listitem">4</div>
            <div role="listitem">5</div>
            <div role="listitem">6</div>
            <div role="listitem">7</div>
          </div>
        </div>
      </div>
    </div>
    Login or Signup to reply.
  2. One way to achieve this would be to use a function which you call recursively via setTimeout(), incrementing the index with each call. Note that you can use the modulo operator to make sure the index never goes out of bounds.

    let elm = document.querySelector('#pane-side');
    let listitems = elm.children[0].children[0].children[0].children;
    
    const scrollToItem = index => {
      listitems[index % listitems.length].scrollIntoView({
        behavior: "smooth",
        block: "end",
        inline: "nearest"
      });
      setTimeout(() => scrollToItem(++index), 1000);
    }
    scrollToItem(0);
    

    Here’s working example: https://jsfiddle.net/6srbtvjz/.
    Note that I had to place it in a jsFiddle as the scrolling caused issues with the SO layout when using a snippet.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search