Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery custom scrollbar and lazy load

I have container with Custom content scroller jQuery custom content scroller: This code:

(function($){
    $(window).load(function(){
        $(".content").mCustomScrollbar({
            scrollButtons: { enable: true },
            mouseWheelPixels: 250
        });
    });
})(jQuery);

And I would like to use it with Lazy Load:

$(function() {
  $("img.lazy").lazyload({
     effect : "fadeIn",
     container: $(".content")
  });
});

I think it should be working with callbacks function from Scroller page but I'm not good with jquery so my results are unsuccessful.

When I use my code like below it loads all images at page load:

$(function() {
  $("img.lazy").lazyload({
     effect : "fadeIn",
     container: $(".mCSB_container")
  });
});

The authos says this can be done by writing a simple js function and call it on whileScrolling event.

Thanks for any help.

like image 985
Jan Fryauf Avatar asked Mar 20 '13 18:03

Jan Fryauf


2 Answers

Your attempt to use container does not work because mCustomScrollbar does not use scrolling containers, but relative positioning in a overflow: hidden container to achieve scrolling. The cleanest approach I can think of is to use a custom [event to trigger lazyload][1]. Here is how I'd do it for the example file given by Hasan Gürsoy:

<script>
$(document).ready(function () {
    var filledHeight = 250;
    $(window).load(function () {
        $(".scroll").height($(window).height() - filledHeight);
        $(".scroll").mCustomScrollbar({ scrollButtons: { enable: true },
        mouseWheelPixels: 250,
        callbacks: { whileScrolling: function() {
            var scroller = $(".mCSB_container");
            var scrollerBox = scroller.closest(".mCustomScrollBox");
            $(".scroll img.lazy").filter(function() {
                var $this = $(this);
                if($this.attr("src") == $this.data("src")) return false;
                var scrollerTop = scroller.position().top;
                var scrollerHeight = scrollerBox.height();
                var offset = $this.closest("div").position();
                return (offset.top < scrollerHeight - scrollerTop);
            }).trigger("lazyScroll");
            }}});

        $("img.lazy").lazyload({ event: "lazyScroll" });
    });
});
</script>

I also use a whileScrolling callback, but only to check which of the img.lazy images are visible. They are if their relative position to the container is not larger than the height of the container minus its CSS top property. (Assuming you always scroll top → down; this setup does not recognize images which are invisibile because you scrolled too far down.) For these images, the function then triggers the custom lazyScroll event, which is the event that lazyload uses to trigger loading images.

Note that this solution is not very portable yet: You'd have to replace the queries for the .mCSB_container and .mCustomScrollBox with ones that fetch you the elements associated with the current scroll box for the script to work in situations with more than one mCustomScrollbar. In a real-world scenario, I'd also cache the jQuery objects instead of recreating them on each invocation of the callback.

like image 77
Phillip Avatar answered Oct 22 '22 00:10

Phillip


I think the author meant additionally hooking into the whileScrolling event like this:

(function($){

    $(window).load(function(){

        $("#content_1").mCustomScrollbar({
            scrollButtons:{
                enable:true
            },
            callbacks:{
                whileScrolling:function(){ WhileScrolling(); } 
            }
        });

        function WhileScrolling(){
            $("img.lazy").lazyload();
        }

    });

})(jQuery);

where the HTML container is like the following:


<div id="content_1" class="content">
    <p>Lorem ipsum dolor sit amet. Aliquam erat volutpat. Maecenas non tortor nulla, non malesuada velit.</p>
    <p>
        <img class="lazy img-responsive" data-original="/img/bmw_m1_hood.jpg" width="765" height="574" alt="BMW M1 Hood"><br/>
        <img class="lazy img-responsive" data-original="/img/bmw_m1_side.jpg" width="765" height="574" alt="BMW M1 Side"><br/>
        <img class="lazy img-responsive" data-original="/img/viper_1.jpg" width="765" height="574" alt="Viper 1"><br/>
        <img class="lazy img-responsive" data-original="/img/viper_corner.jpg" width="765" height="574" alt="Viper Corner"><br/>
        <img class="lazy img-responsive" data-original="/img/bmw_m3_gt.jpg" width="765" height="574" alt="BMW M3 GT"><br/>
        <img class="lazy img-responsive" data-original="/img/corvette_pitstop.jpg" width="765" height="574" alt="Corvette Pitstop"><br/> 
    </p>
    <p>Aliquam erat volutpat. Maecenas non tortor nulla, non malesuada velit. Nullam felis tellus, tristique nec egestas in, luctus sed diam. Suspendisse potenti. </p>
    <p>Consectetur adipiscing elit. Nulla consectetur libero consectetur quam consequat nec tincidunt massa feugiat. Donec egestas mi turpis. Fusce adipiscing dui eu metus gravida vel facilisis ligula iaculis. Cras a rhoncus massa. Donec sed purus eget nunc placerat consequat.</p>
    <p>Cras venenatis condimentum nibh a mollis. Duis id sapien nibh. Vivamus porttitor, felis quis blandit tincidunt, erat magna scelerisque urna, a faucibus erat nisl eget nisl. Aliquam consequat turpis id velit egestas a posuere orci semper. Mauris suscipit erat quis urna adipiscing ultricies. In hac habitasse platea dictumst. Nulla scelerisque lorem quis dui sagittis egestas.</p> 
    <p>Etiam sed massa felis, aliquam pellentesque est.</p>
    <p>the end.</p>
</div>

To reduce the number of lazyload() during scrolling, we could use for example the mcs.top property for the scrolling content’s top position (pixels):

function WhileScrolling()
{
    // Debug:
    // console.log( 'top: ' + mcs.top );

    // Run lazyload in 10 pixel steps (adjust to your needs) 
    if( 0 == mcs.top % 10 )
    {
        // Run lazyload on the "div#conent_1" box:
        $("#content_1 img.lazy").lazyload();

        // Debug:
        //console.log( 'lazyload - mcs.top: ' + mcs.top );
    }
}

where we restrict the layzload selector, so we don't have to find all the images in the whole DOM tree.

I noticed that in Internet Explorer 11, the mcs.top can be floating numbers but it's alwyas whole integers in Chrome.

So we could floor it with Math.floor().

To further reduce the lazyload calls, we could additionally compare mcs.top to it's previous value:

var mcsTopPrev = 0;
var mcsTop = 0;
function WhileScrolling()
{
    // Fix the Chrome vs Internet Explorer difference
    mcsTop = Math.floor( mcs.top );

    // Current vs previous 
    if(  mcsTop != mcsTopPrev )
    {
        // Run lazyload in 10px scrolling steps (adjust to your needs)
        if( 0 == mcsTop % 10 )
        {
            $("#cphContent_lReferences img.lazy").lazyload();
        }
    }
    mcsTopPrev =  mcsTop;
}
like image 2
birgire Avatar answered Oct 22 '22 00:10

birgire