Skip to content
Browse files

Refactor, introduce "offset" feature

  • Loading branch information...
1 parent e084cf0 commit 7f047655e760d29d4544bcd8de6e50c1e3a9163a @jedmao jedmao committed Jul 24, 2013
Showing with 84 additions and 49 deletions.
  1. +21 −0 README.md
  2. +63 −49 jquery.inview.js
View
21 README.md
@@ -153,6 +153,27 @@ through, looking for the elements tied to the 'inview' event.
This way the user can treat it like a native event on the page.
+## Offset Feature
+
+If you decide to use this code for lazy loading images, you might be interested
+in 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:
+
+```html
+<img data-offset="300">
+```
+
+or in JavaScript:
+
+```js
+$('img').attr('data-offset', 300);
+```
+
+This allows the image to preload as it approaches the viewport so there's a
+better chance it will complete before the user even sees it.
+
+
[jQuery for Designers]: http://jqueryfordesigners.com/
[.net magazine]: http://www.netmag.co.uk/
[lazyload plugin]: http://www.appelsiini.net/projects/lazyload
View
112 jquery.inview.js
@@ -1,23 +1,30 @@
/**
* author Remy Sharp
* url http://remysharp.com/2009/01/26/element-in-view-event-plugin/
+ * fork https://github.com/zuk/jquery.inview
*/
-(function ($) {
+(function($) {
'use strict';
- var shouldCheckInView = false;
+ function getScrollTop() {
+ return window.pageYOffset ||
+ document.documentElement.scrollTop ||
+ document.body.scrollTop;
+ }
function getViewportHeight() {
var height = window.innerHeight; // Safari, Opera
// if this is correct then return it. iPad has compat Mode, so will
// go into check clientHeight (which has the wrong value).
- if (height) { return height; }
+ if (height) {
+ return height;
+ }
var mode = document.compatMode;
- if ( (mode || !$.support.boxModel) ) { // IE, Gecko
+ if ((mode || !$.support.boxModel)) { // IE, Gecko
height = (mode === 'CSS1Compat') ?
- document.documentElement.clientHeight : // Standards
- document.body.clientHeight; // Quirks
+ document.documentElement.clientHeight : // Standards
+ document.body.clientHeight; // Quirks
}
return height;
@@ -28,68 +35,75 @@
// This works-around iOS < 4 on iPad giving incorrect value
// cf http://bugs.jquery.com/ticket/6446#comment:9
var curtop = 0;
- for (var obj = debug; obj !== null; obj = obj.offsetParent) {
+ for (var obj = debug; obj; obj = obj.offsetParent) {
curtop += obj.offsetTop;
}
return curtop;
}
- function check_inview() {
- var vpH = getViewportHeight(),
- scrolltop = (window.pageYOffset ?
- window.pageYOffset :
- document.documentElement.scrollTop ?
- document.documentElement.scrollTop :
- document.body.scrollTop),
+ function checkInView() {
+ var viewportTop = getScrollTop(),
+ viewportBottom = viewportTop + getViewportHeight(),
elems = [];
// naughty, but this is how it knows which elements to check for
- $.each($.cache, function () {
+ $.each($.cache, function() {
if (this.events && this.events.inview) {
elems.push(this.handle.elem);
}
});
- if (elems.length) {
- $(elems).each(function () {
- var $el = $(this),
- top = offsetTop(this),
- height = $el.height(),
- inview = $el.data('inview') || false;
+ $(elems).each(function() {
+ var $el = $(this),
+ elTop = offsetTop(this),
+ elHeight = $el.height(),
+ elBottom = elTop + elHeight,
+ wasInView = $el.data('inview') || false,
+ offset = $el.data('offset') || 0,
+ inView = elTop > viewportTop && elBottom < viewportBottom,
+ isBottomVisible = elBottom + offset > viewportTop && elTop < viewportTop,
+ isTopVisible = elTop - offset < viewportBottom && elBottom > viewportBottom,
+ inViewWithOffset = inView || isBottomVisible || isTopVisible ||
+ (elTop < viewportTop && elBottom > viewportBottom);
- if (scrolltop > (top + height) || scrolltop + vpH < top) {
- if (inview) {
- $el.data('inview', false);
- $el.trigger('inview', [ false ]);
- }
- } else if (scrolltop < (top + height)) {
- var visPart = ( scrolltop > top ? 'bottom' : (scrolltop + vpH) < (top + height) ? 'top' : 'both' );
- if (!inview || inview !== visPart) {
- $el.data('inview', visPart);
- $el.trigger('inview', [ true, visPart]);
- }
+ if (inViewWithOffset) {
+ var visPart = (isTopVisible) ? 'top' : (isBottomVisible) ? 'bottom' : 'both';
+ if (!wasInView || wasInView !== visPart) {
+ $el.data('inview', visPart);
+ $el.trigger('inview', [true, visPart]);
}
- });
- }
+ } else if (!inView && wasInView) {
+ $el.data('inview', false);
+ $el.trigger('inview', [false]);
+ }
+ });
}
- var $win = $(window);
+ function createFunctionToLimitExecutionToOncePerDelay(fn, delay) {
+ var shouldRun = false;
+ var timer = null;
- // ready.inview kicks the event to pick up any elements already in view.
- // note however, this only works if the plugin is included after the elements are bound to 'inview'
- // you can call it manually in your application by calling $(window).trigger('checkInView');
- $win.on('checkInView.inview click.inview ready.inview', check_inview);
+ function runOncePerDelay() {
+ if (timer !== null) {
+ shouldRun = true;
+ return;
+ }
+ shouldRun = false;
+ fn();
+ timer = setTimeout(function() {
+ timer = null;
+ if (shouldRun) {
+ runOncePerDelay();
+ }
+ }, delay);
+ }
- $win.on('scroll.inview resize.inview', function() {
- shouldCheckInView = true;
- });
+ return runOncePerDelay;
+ }
- // Source: http://ejohn.org/blog/learning-from-twitter/
- setInterval(function() {
- if ( shouldCheckInView ) {
- shouldCheckInView = false;
+ // ready.inview kicks the event to pick up any elements already in view.
+ // note however, this only works if the plugin is included after the elements are bound to 'inview'
+ var runner = createFunctionToLimitExecutionToOncePerDelay(checkInView, 100);
+ $(window).on('checkInView.inview click.inview ready.inview scroll.inview resize.inview', runner);
- check_inview();
- }
- }, 100);
})(jQuery);

0 comments on commit 7f04765

Please sign in to comment.
Something went wrong with that request. Please try again.