user7182935
user7182935

Reputation:

Convert a function to be able to use it as an "on" event

I currently have this function:

function isInView() {
  var windowStart = $(window).scrollTop();
  var windowEnd = windowStart + $(window).height();

  $('.box').each(function() {
    var box = $(this);
    var start = box.offset().top;
    var end = start + box.height();

    if (windowStart <= start && windowEnd >= end) {
      box.addClass('active');
    } else {
      box.removeClass('active');
    }
  });
}

$(document).scroll(isInView);

This function checks if an entire element is visible in the viewport (jsfiddle) and adds/removes the active class from the element.

However, I want to be able to use this function as an "on" event, so that I can apply to many different elements. This would mean somehow converting the function and assigning it its own custom on event, like isinview.

In other words, I'd like to be able to use it like this:

$('.box').on('isinview', function () {
    if (elementIsInView) {
        // make the box red
    } else {
        // make the box the original color
    }
});

Or for a different element:

$('.nav').on('isinview', function () {
    if (elementIsInView) {
        // make the nav bigger
    } else {
        // make the nav the original height
    }
});

How can I do this?

Upvotes: 0

Views: 58

Answers (2)

Taplar
Taplar

Reputation: 24965

jQuery(function($) {
    var $window = $(window);

    function notifyElementsInView() {
        var windowStart = $window.scrollTop(),
            windowEnd = windowStart + $window.height();
		
		$('.bindInView').each(function() {
			var $element = $(this),
				start = $element.offset().top,
				end = start + $element.height();
			
			if (windowStart <= start && windowEnd >= end) {
				$element.trigger('viewEnter');
			} else {
				$element.trigger('viewExit');
			}
		});
    }
	
	$('.box')
		.on('viewEnter', function() {
			$(this).addClass('active');
		})
		.on('viewExit', function() {
			$(this).removeClass('active');
		});
	
	notifyElementsInView();
	$(document).on('scroll', notifyElementsInView);
	$window.on('resize', notifyElementsInView);
});
body {
    margin: 50px;
}

.container {
    width: 300px;
    background: lightgrey;
    padding: 50px;
}

.box {
    display: block;
    width: 100%;
    height: 300px;
    background: grey;
}

.box:not(:last-of-type) {
    margin-bottom: 50px;
}

.box.active {
    background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
    <div class="box"></div>
    <div class="box bindInView"></div>
    <div class="box bindInView"></div>
</div>

Upvotes: 1

adeneo
adeneo

Reputation: 318302

You could rewrite it as a plugin, and trigger the events

$.fn.isInView = function() {
  var self = this;
  $(window).on('scroll resize', function() {
    var windowStart = $(window).scrollTop();
    var windowEnd   = windowStart + $(window).height();

    self.each(function() {
      var box   = $(this);
      var start = box.offset().top;
      var end   = start + box.height();

      if (windowStart <= start && windowEnd >= end) {
        if (!box.data('inview')) box.trigger('isinview').data('inview', true);
      } else {
        if (box.data('inview') ) box.trigger('hasleftview').data('inview', false);
      }
    });
  }).trigger('scroll');
  return self;
}

$('.box')
  .on('isinview', function() {
    $(this).addClass('active');
}).on('hasleftview', function() {
    $(this).removeClass('active');
}).isInView(); // call plugin after events are bound
body {
  margin: 50px;
}
.container {
  width: 300px;
  background: lightgrey;
  padding: 50px;
}
.box {
  display: block;
  width: 100%;
  height: 300px;
  background: grey;
}
.box:not(:last-of-type) {
  margin-bottom: 50px;
}
.box.active {
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</div>

Upvotes: 1

Related Questions