Search code examples
javascriptloopsonscrollarray.prototype.map

Adding class on scroll to each element of an array


Hello guys Im trying to add a class to an element once it shows on the view using vanilla javascript

<main>
        <section class="fs-sect" data-name="Banana"></section>
        <section class="fs-sect" data-name="Apple"></section>
        <section class="fs-sect" data-name="Avocado"></section>
        <section class="fs-sect" data-name="Orange"></section>
        <section class="fs-sect" data-name="Grapes"></section>
    </main>

This is my list of sections once I scroll to each section I want to add an active class and remove this class from any other sections

<script>
const Myarray = document.querySelectorAll('.fs-sect');
// convert NodeList to array and map it
const Newarray = Array.from(Myarray).map((num,index) =>{
    const dataname = num.dataset.name;
    const myoffset = num.offsetTop;

    window.onscroll = function (e) {  
        let position_y = window.scrollY;
        if(position_y >= myoffset){
            document.querySelectorAll('.fs-sect').classList.remove('active-section');
            num.classList.add('active-section');
        } 
        console.log(position_y);
    } 
    return (
        //using index as ID and displaying data-attribute with offset position
        console.log(`I am a ${dataname} and my ID is ${index} and Im positioned at ${myoffset}`)
    );
});
</script>

I only managed to loop into the array get the index element.offset of each element but still need to add a class once I scroll,

Thanks for the help


Solution

  • Working example. Note: class changes are visible in Developer tools only.

    /* Prepare: */
    
    function posY(elm) {
      var test = elm,
        top = 0;
    
      while (!!test && test.tagName.toLowerCase() !== "body") {
        top += test.offsetTop;
        test = test.offsetParent;
      }
    
      return top;
    }
    
    function viewPortHeight() {
      var de = document.documentElement;
    
      if (!!window.innerWidth) {
        return window.innerHeight;
      } else if (de && !isNaN(de.clientHeight)) {
        return de.clientHeight;
      }
    
      return 0;
    }
    
    function scrollY() {
      if (window.pageYOffset) {
        return window.pageYOffset;
      }
      return Math.max(document.documentElement.scrollTop, document.body.scrollTop);
    }
    
    function checkVisible(elm, eval) {
      eval = eval || "visible";
      var vpH = viewPortHeight(), // Viewport Height
        st = scrollY(), // Scroll Top
        y = posY(elm),
        elementHeight = elm.offsetHeight;
    
      if (eval == "visible") return ((y < (vpH + st)) && (y > (st - elementHeight)));
      if (eval == "above") return ((y < (vpH + st)));
    }
    
    let sectionsVisible = '';
    
    // Onscroll
    
    const onscroll = function(e) {
      let sections = document.querySelectorAll('.fs-sect');
      let visibleSections = [];
      for (let section of sections) {
        const isVisible = checkVisible(section);
        section.classList.toggle('active-section', isVisible);
        if (isVisible) visibleSections.push(section.getAttribute('data-name'));
      }
      if (sectionsVisible != visibleSections.join(',')) {
        sectionsVisible = visibleSections.join(',');
        console.log('Visible:', sectionsVisible);
      }
    };
    
    window.onscroll = onscroll;
    onscroll();
    section {
      height: 150px;
      background-color: #EEE;
      margin-bottom: 10px;
      position: relative;
    }
    
    section:after {
      display: block;
      position: absolute;
      right: 4px;
      top: 4px;
      content: attr(data-name);
    }
    
    section.active-section {
      background-color: #666;
      color: white;
    }
    <main>
      <section class="fs-sect" data-name="Banana"></section>
      <section class="fs-sect" data-name="Apple"></section>
      <section class="fs-sect" data-name="Avocado"></section>
      <section class="fs-sect" data-name="Orange"></section>
      <section class="fs-sect" data-name="Grapes"></section>
    </main>