Instantly share code, notes, and snippets.

Embed
What would you like to do?
lazyload.js (c) Lorenzo Giuliani
/* lazyload.js (c) Lorenzo Giuliani
* MIT License (http://www.opensource.org/licenses/mit-license.html)
*
* expects a list of:
* `<img src="blank.gif" data-src="my_image.png" width="600" height="400" class="lazy">`
*/
!function(window){
var $q = function(q, res){
if (document.querySelectorAll) {
res = document.querySelectorAll(q);
} else {
var d=document
, a=d.styleSheets[0] || d.createStyleSheet();
a.addRule(q,'f:b');
for(var l=d.all,b=0,c=[],f=l.length;b<f;b++)
l[b].currentStyle.f && c.push(l[b]);
a.removeRule(0);
res = c;
}
return res;
}
, addEventListener = function(evt, fn){
window.addEventListener
? this.addEventListener(evt, fn, false)
: (window.attachEvent)
? this.attachEvent('on' + evt, fn)
: this['on' + evt] = fn;
}
, _has = function(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
;
function loadImage (el, fn) {
var img = new Image()
, src = el.getAttribute('data-src');
img.onload = function() {
if (!! el.parent)
el.parent.replaceChild(img, el)
else
el.src = src;
fn? fn() : null;
}
img.src = src;
}
function elementInViewport(el) {
var rect = el.getBoundingClientRect()
return (
rect.top >= 0
&& rect.left >= 0
&& rect.top <= (window.innerHeight || document.documentElement.clientHeight)
)
}
var images = new Array()
, query = $q('img.lazy')
, processScroll = function(){
for (var i = 0; i < images.length; i++) {
if (elementInViewport(images[i])) {
loadImage(images[i], function () {
images.splice(i, i);
});
}
};
}
;
// Array.prototype.slice.call is not callable under our lovely IE8
for (var i = 0; i < query.length; i++) {
images.push(query[i]);
};
processScroll();
addEventListener('scroll',processScroll);
}(this);
@pocketjoso

This comment has been minimized.

Show comment
Hide comment
@pocketjoso

pocketjoso Apr 17, 2014

Hi, I know this code probably hasn't been touched in a while, but as I was going to use it today I realized these line are broken:

loadImage(images[i], function () {
    images.splice(i, i);
}

The second parameter of the splice call should be 1 and not i - because you only want to remove the i element from the array, right? Not i nr of elements.

By the time the splice call is made, via your loadImage callback function, your i will already be set to be the length of the whole images array - as the for loop controlling it will already have finished. You have to create another scope for your i, either by passing it in to loadImage, or perhaps just by wrapping these three line in an IIFE:

(function(i){
    loadImage(images[i], function () {
       images.splice(i, 1);
   }
}(i);
..

I did something else for my purpose, but I think something like this should work for a general case.

pocketjoso commented Apr 17, 2014

Hi, I know this code probably hasn't been touched in a while, but as I was going to use it today I realized these line are broken:

loadImage(images[i], function () {
    images.splice(i, i);
}

The second parameter of the splice call should be 1 and not i - because you only want to remove the i element from the array, right? Not i nr of elements.

By the time the splice call is made, via your loadImage callback function, your i will already be set to be the length of the whole images array - as the for loop controlling it will already have finished. You have to create another scope for your i, either by passing it in to loadImage, or perhaps just by wrapping these three line in an IIFE:

(function(i){
    loadImage(images[i], function () {
       images.splice(i, 1);
   }
}(i);
..

I did something else for my purpose, but I think something like this should work for a general case.

@monrifnet

This comment has been minimized.

Show comment
Hide comment
@monrifnet

monrifnet Mar 28, 2017

Much like pocketjoso before, I realize this code hasn't been touched in a few years, but here's a few lines I added so that images with "lazy" class but no "data-src" are ignored and de-classed. Not doing so could result in a bunch of www.domain.com/null unwanted calls.

This

function loadImage (el, fn) {
    var img = new Image()
      , src = el.getAttribute('data-src');
    img.onload = function() {
      if (!! el.parent)
        el.parent.replaceChild(img, el)
      else
        el.src = src;
      fn? fn() : null;
    }
    img.src = src;
}

Would become

function loadImage (el, fn) {
    var img = new Image()
      , src = el.getAttribute('data-src');
    if (!src) {
        el.className = el.className.replace(/(^|\s)lazy(\s|$)/i, ' ');
        return;
    }
    img.onload = function() {
      if (!! el.parent)
        el.parent.replaceChild(img, el)
      else
        el.src = src;
      fn? fn() : null;
    }
    img.src = src;
}

monrifnet commented Mar 28, 2017

Much like pocketjoso before, I realize this code hasn't been touched in a few years, but here's a few lines I added so that images with "lazy" class but no "data-src" are ignored and de-classed. Not doing so could result in a bunch of www.domain.com/null unwanted calls.

This

function loadImage (el, fn) {
    var img = new Image()
      , src = el.getAttribute('data-src');
    img.onload = function() {
      if (!! el.parent)
        el.parent.replaceChild(img, el)
      else
        el.src = src;
      fn? fn() : null;
    }
    img.src = src;
}

Would become

function loadImage (el, fn) {
    var img = new Image()
      , src = el.getAttribute('data-src');
    if (!src) {
        el.className = el.className.replace(/(^|\s)lazy(\s|$)/i, ' ');
        return;
    }
    img.onload = function() {
      if (!! el.parent)
        el.parent.replaceChild(img, el)
      else
        el.src = src;
      fn? fn() : null;
    }
    img.src = src;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment