Reputation:
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
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
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