javascriptjqueryjquery-waypoints

How to trigger a class that is only in view with wapoints


I have multiple sections with the class blockList li throughout each of these sections. How am I able to trigger only the current blockList li items for the ones that are in view? Currently, once any of the list items are in view they all fire throughout the page, even though they are not in view.

The snippet below illustrates the issue I am having.

$('.blockList').waypoint(function() {
		$('.blockList li').each(function(index) {
			setTimeout(()=>{
				$(this).addClass('active');
			}, 200*index);			 
		});
	}, {
		offset: '60%'
	});
#blue, #red {
  width: 100%;
  height: 100vh;
}
#blue {
  background: blue;
}
#red {
  background: red;
}
.blockList {
	margin: 15px 0;
	text-align: left;
}
.blockList li {
	font-size: 1rem;
	color: #FFF;
	margin: 20px 0;
	opacity: 0;
	-webkit-transition: ease 0.4s;transition: ease 0.4s;
	-webkit-transform: translateY(-15px);transform: translateY(-15px);
}
.blockList li.active {
	opacity: 1;
	-webkit-transform: translateY(0px);transform: translateY(0px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js"></script>
<section id="blue">
  <ul class="blockList">
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
  </ul>
</section>
<section id="red">
  <ul class="blockList">
    <li>E</li>
    <li>F</li>
    <li>G</li>
    <li>H</li>
  </ul>
</section>


Solution

  • You are adding active class to li items for all of them.

    $('.blockList li').each(function(index) {
        setTimeout(()=>{
            $(this).addClass('active');
        }, 200*index);           
    });
    

    TL:TR

    In shorter terms. you are basicaly adding active class two times to each list element. Since you are adding it at the begging and then adding it at the 60% offset.


    It loops trough all li and puts active class. So therefore it doesnt have to be in view, since its adding on load.

    One solution might be getting position in browser of second object, or make a compact system that it checks all of them, places in array. So it would check its position -> on scroll check if reached any of the elements -> if reached, add active class to the coresponding ID.

    var p = $( "#red" ).position;
    var Positions = {top: p.top};
    

    Then get the your center window position Something like:

    jQuery.fn.center = function () {
        this.css("position","absolute");
        this.css("top", Math.max(0, (($(window).height() - $(this).outerHeight()) / 2) + 
                                                    $(window).scrollTop()) + "px");
        this.css("left", Math.max(0, (($(window).width() - $(this).outerWidth()) / 2) + 
                                                    $(window).scrollLeft()) + "px");
        return this;
    }
    

    Then compare them, if it reached the element.

    Then get its id and add .active class to the #red li, not genaraly li.

    What I would do in this situation:

    var global_list = {}; var elemCount = 0;
    $(document).ready(function() {
    	//call initFunc, after its complete, call elimination (so it would check on load) and then set on scroll.
    	initFunc(function() {
        elimination();
        $(document).on('scroll', function() { elimination() });
      });
    
    	//This function is basicaly your startup.
      function initFunc(int) { 
          $('.blockList').each(function() {
              var p = $(this).position(); //Lets get its position.
              var id = $(this).attr('id'); //Lets get its ID
              global_list[id] = p.top; //Lets asign ID -> topPosition, so { first: 8 }...
              elemCount++;
          });
          
          int();
      }
      
      //This assigns needed stuff for allready reached objects.
      function elimination() { 
    
        
        if(elemCount != 0) { //Did we allready show all elements?
          var cb = $(this).scrollTop() + ($(this).height()), ct = $(this).scrollTop(); //Gets top position, and bottom.
          var cP = ct + ((cb - ct)/2); //Gets your center point of viewport - ad half screen size to top;
          for(var k in global_list) { //Loop trough all element that are left and see if we did scroll.
            if(global_list[k] <= cP) { //Lets check if user scolled to it.
         				var ic=0;
            		$('#'+k+' li').each(function() {
                	setTimeout(()=>{
                    $(this).addClass('active');
                  }, 200*ic);	
                  ic++
                });
                delete global_list[k]; //Lets delete allready assigned classes
                elemCount--; //Decreses elements count, so eventualy once all reached, it becomes 0;
            }
          }
        }
      }
    });
    #first {
      height: 1000px;
    }
    
    #second {
      height: 1000px;
    }
    
    .beatiful {
      background: yellow;
    }
    
    .div_div li {
      	font-size: 1rem;
    	color: #000;
    	margin: 20px 0;
    	opacity: 0;
    	-webkit-transition: ease 0.4s;transition: ease 0.4s;
    	-webkit-transform: translateY(-15px);transform: translateY(-15px);
    }
    
    .div_div li.active {
      	opacity: 1;
    	-webkit-transform: translateY(0px);transform: translateY(0px);
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <div class='div_div' id='first'>
      <ul class="blockList" id='first'>
        <li>A</li>
        <li>B</li>
        <li>C</li>
        <li>D</li>
      </ul>
    </div>
    <div class='div_div' id='second'>
      <ul class="blockList" id='second'>
        <li>A</li>
        <li>B</li>
        <li>C</li>
        <li>D</li>
      </ul>
    </div>