user7182935 user7182935 - 14 days ago 6
jQuery Question

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?

Answer

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>

Comments