3
\$\begingroup\$

I have posted such question at StackOverflow but the single answer I got there was to ask here.
My task is to get elements fading in while the user is scrolling. Here is my link - http://layot.prestatrend.com/ I have made it with the help of such jQuery code I've gathered from two sources:

<script type="text/javascript">
 $(document).ready( function() {

 tiles = $('.ajax_block_product').fadeTo(0,0);

 $(window).scroll(function(d,h) {
    tiles.each(function(i) {
        a = $(this).offset().top + $(this).height();
        b = $(window).scrollTop() + $(window).height();
        if (a < b) $(this).fadeTo(500,1);
    });
 });

 function inWindow(s){
  var scrollTop = $(window).scrollTop();
  var windowHeight = $(window).height();
  var currentEls = $(s);
  var result = [];
  currentEls.each(function(){
    var el = $(this);
    var offset = el.offset();
    if(scrollTop <= offset.top && (el.height() + offset.top) < (scrollTop + windowHeight))
      result.push(this);
  });
  return $(result);
}

inWindow('.ajax_block_product').fadeTo(0,1);

});
</script>

Is this an elegant solution or is there a way to make the code shorter and more elegant?

\$\endgroup\$
1
  • \$\begingroup\$ Can you clarify what you mean by "fade for elements while scrolling"? I see nothing on the page that does fade in while scrolling, I just see things fading in as you hover over them \$\endgroup\$ Commented Feb 6, 2012 at 19:31

1 Answer 1

2
\$\begingroup\$

The onScroll event is generally very performance hungry, since it is called quite often, while scrolling. Looping through all "ajax_block_product" elements on every singel call, even if most of them might be outside of the viewport, makes it even worse. But you can use some specialities of JS to optimize it. As a short intro: In JS you can set an array element at a defined index, leaving the ones in between undefined while having the length of the array set to the highest index defined.

a[100] = 'one';
a[1000] = 'two';
for (var i = 0; i < a.length; i++) {
    console.log('iterate'); // called 1000 times
}
for (var elm in a) {
    console.log('iterate'); // called two times
}

Now if you loop through the array with a typical for(var i = 0; i < a.length; i++) you will have 1000 iterations BUT since an array is also an object in JS a for(elm in a) would only iterate 2 times. We can now use this to store all Y-positions of "ajax_block_product" elements as indexes of an array, than determine the dimension of the current viewport and cut out only those element who are inside that range.

$(document).ready(function () {
    var tiles = $('.ajax_block_product'),
        winHeight = $(window).height(),
        posArr = [];

    tiles.each(function () {
        var pos = $(this).offset().top;
        posArr[pos] = $(this);
    });

    $(window).scroll((function fadeIn() {
        var sTop = $(window).scrollTop(),
            range = posArr.slice(sTop, sTop + winHeight);
        range.forEach(function (elm) {
            elm.css('opacity', 1);
        });
        return fadeIn;
    }()));
});

In this example I've used CSS3: transition: opacity .5s ease-in; for the fade in. You need to check out how to do this with jQuery's fadeIn, if needed...

Last but not least, the onScroll event callback is somehow special. It a self-executing, self-referencing function. It is called once, when it's defined, to initially show all elements already in the viewport and then returns a reference to itself for later onScroll event calls.

Hope this could help you, even if it's some time ago, you asked this question...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.