Open jamesryan-dev opened 5 years ago
With offset to preloading the image when it's getting close to entering the viewport. To do this, you can now add a data-offset attribute to your target element. For example:
<img data-offset="300">
also support visible area using third parameter on on, one event for example:
$('div').on('inview', function (event, visible, topOrBottomOrBoth) {
if (visible == true) {
// element is now visible in the viewport
if (topOrBottomOrBoth == 'top') {
// top part of element is visible
} else if (topOrBottomOrBoth == 'bottom') {
// bottom part of element is visible
} else {
// whole part of element is visible
}
} else {
// element has gone out of viewport
}
});
updated jquery.inview:
/**
* author Christopher Blum
* - based on the idea of Remy Sharp, http://remysharp.com/2009/01/26/element-in-view-event-plugin/
* - forked from http://github.com/zuk/jquery.inview/
*/
(function (factory) {
if (typeof define == 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var inviewObjects = [], viewportSize, viewportOffset,
d = document, w = window, documentElement = d.documentElement, timer;
$.event.special.inview = {
add: function(data) {
inviewObjects.push({ data: data, $element: $(this), element: this });
// Use setInterval in order to also make sure this captures elements within
// "overflow:scroll" elements or elements that appeared in the dom tree due to
// dom manipulation and reflow
// old: $(window).scroll(checkInView);
//
// By the way, iOS (iPad, iPhone, ...) seems to not execute, or at least delays
// intervals while the user scrolls. Therefore the inview event might fire a bit late there
//
// Don't waste cycles with an interval until we get at least one element that
// has bound to the inview event.
if (!timer && inviewObjects.length) {
timer = setInterval(checkInView, 250);
}
},
remove: function(data) {
for (var i=0; i<inviewObjects.length; i++) {
var inviewObject = inviewObjects[i];
if (inviewObject.element === this && inviewObject.data.guid === data.guid) {
inviewObjects.splice(i, 1);
break;
}
}
// Clear interval when we no longer have any elements listening
if (!inviewObjects.length) {
clearInterval(timer);
timer = null;
}
}
};
function getViewportSize() {
var mode, domObject, size = { height: w.innerHeight, width: w.innerWidth };
// if this is correct then return it. iPad has compat Mode, so will
// go into check clientHeight/clientWidth (which has the wrong value).
if (!size.height) {
mode = d.compatMode;
if (mode || !$.support.boxModel) { // IE, Gecko
domObject = mode === 'CSS1Compat' ?
documentElement : // Standards
d.body; // Quirks
size = {
height: domObject.clientHeight,
width: domObject.clientWidth
};
}
}
return size;
}
function getViewportOffset() {
return {
top: w.pageYOffset || documentElement.scrollTop || d.body.scrollTop,
left: w.pageXOffset || documentElement.scrollLeft || d.body.scrollLeft
};
}
function checkInView() {
if (!inviewObjects.length) {
return;
}
var i = 0, $elements = $.map(inviewObjects, function(inviewObject) {
var selector = inviewObject.data.selector,
$element = inviewObject.$element;
return selector ? $element.find(selector) : $element;
});
viewportSize = viewportSize || getViewportSize();
viewportOffset = viewportOffset || getViewportOffset();
for (; i<inviewObjects.length; i++) {
// Ignore elements that are not in the DOM tree
if (!$.contains(documentElement, $elements[i][0])) {
continue;
}
var $element = $($elements[i]),
elementSize = { height: $element[0].offsetHeight, width: $element[0].offsetWidth },
elementOffset = $element.offset(),
wasInView = $element.data('inview') || false;
// Don't ask me why because I haven't figured out yet:
// viewportOffset and viewportSize are sometimes suddenly null in Firefox 5.
// Even though it sounds weird:
// It seems that the execution of this function is interferred by the onresize/onscroll event
// where viewportOffset and viewportSize are unset
if (!viewportOffset || !viewportSize) {
return;
}
var elBottom = elementOffset.top + elementSize.height,
offset = $element.data('offset') || 0,
isBottomVisible = elBottom + offset >= viewportOffset.top && elementOffset.top <= viewportOffset.top,
viewportBottom = viewportOffset.top + viewportSize.height;
isTopVisible = elementOffset.top - offset <= viewportBottom && elBottom >= viewportBottom,
inView = elementOffset.top >= viewportOffset.top && elBottom <= viewportBottom,
inViewWithOffset = inView || isBottomVisible || isTopVisible || (elementOffset.top <= viewportOffset.top && elBottom >= viewportBottom);
if (inViewWithOffset) {
var visPart = (isTopVisible) ? 'top' : (isBottomVisible) ? 'bottom' : 'both';
if (!wasInView || wasInView !== visPart) {
$element.data('inview', visPart).trigger('inview', [true, visPart]);
}
} else if (!inView && wasInView) {
$element.data('inview', false).trigger('inview', [false]);
}
}
}
$(w).on("scroll resize scrollstop", function() {
viewportSize = viewportOffset = null;
});
// IE < 9 scrolls to focused elements without firing the "scroll" event
if (!documentElement.addEventListener && documentElement.attachEvent) {
documentElement.attachEvent("onfocusin", function() {
viewportOffset = null;
});
}
}));
Has any1 been able to add an offset so isInView triggers slightly before or after element leaves viewport?