简体   繁体   中英

How to add class to only one element that matches condition using jquery?

I'm trying to check if element crossed bottom edge of viewport. If it did, I want to add class start to this element. The problem is that when condition is satisfied class adds to all h2 elements.

Here is my code:

$.fn.checkAnimation = function() {

  var context = this;
  function isElementInViewport(elem) {
    var $elem = context;

    // Get the scroll position of the page.
    var viewportTop = $(window).scrollTop();
    var viewportBottom = viewportTop + $(window).height();

    // Get the position of the element on the page.
    var elemTop = Math.round( $elem.offset().top );
    var elemBottom = elemTop + $elem.height();

    return (elemTop < viewportBottom);
  }

  // Check if it's time to start the animation.
  function checkAnimation() {
      console.log(isElementInViewport($elem));
      var $elem = context;

      // If the animation has already been started
      if ($elem.hasClass('start')) return;

      if (isElementInViewport($elem)) {
          // Start the animation
          context.addClass('start');
      }
  }
  checkAnimation();
  return this;
};
$(window).on('scroll scrollstart touchmove orientationchange resize', function(){
      $('h2').checkAnimation();
  });

You'll need to change your checkAnimation jQuery plugin to loop through all elements in the jQuery object and process them individually or call your function like this

$('h2').each(function(){
    $(this).checkAnimation();
}

Here is what I mean by processing the elements individually inside the plugin:

$.fn.checkAnimation = function() {

    function isElementInViewport($elem) {
        var viewportTop = $(window).scrollTop();
        var viewportBottom = viewportTop + $(window).height();

        var elemTop = Math.round( $elem.offset().top );
        var elemBottom = elemTop + $elem.height();

        return (elemTop < viewportBottom);
    }

    function checkAnimation() {
        var $elem = $(this);
        if ($elem.hasClass('start')) return;

        if (isElementInViewport($elem)) {
           $elem.addClass('start');
        }
     }
     return this.each(checkAnimation);
};

If you use this version of the plugin you can call it like this:

$('h2').checkAnimation();

It will add the class only to the element that matches the condition not to all the element in the jQuery object you've called the function on.

Should be $elem.addClass('start'); instead and remove the var $elem = context; statement like :

function checkAnimation() {
  console.log(isElementInViewport($elem));

  // If the animation has already been started
  if ($elem.hasClass('start')) return;

  if (isElementInViewport($elem)) {
      // Start the animation
      $elem.addClass('start');
  }
}

Hope this helps.

this inside a jQuery plugin is the jQuery object that contains the whole collection of elements represented by the previous selector/filter.

In order to treat each element in the collection as an individual instance you need to loop through the initial this .

Very basic pattern:

$.fn.pluginName = function(options){
      // return original collection as jQuery to allow chaining
      // loop over collection to access individual elements
      return this.each(function(i, elem){
           // do something with each element instance 
           $(elem).doSomething(); // elem === this also               
      });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM