Image lazy loading

Lazy loading of page images is due to limited browser loading threads. When a page is loaded with too many images, it will seriously affect the loading of other necessary files (such as CSS, JS, etc.), which will cause a poor user experience, and it will also delay the execution of the page load event processing logic, so we can make the visible images load first.

Lazy loading image plug-in

;
(function(undefined) {
    // "use strict"
    var _global;

    The constructor initializes setting
    function extend(o, n, override) {
        for (var key in n) {
            if (n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)) {
                o[key] = n[key];
            }
        }
        return o;
    };

    // Plugin constructor - returns array structure
    function Lazyload(id) {
        this.container = document.getElementById(id);
        // Cache images
        this.imgs = this.getImgs();
        // Execute logic
        this.init();
    };

    Lazyload.prototype = {
        constructor: this.// Start executing logic
        init: function() {},
        // Lazy loading of images
        getImgs: function() {},
        // Load the image
        update: function() {},
        // Check whether the image is visible
        shouldShow: function(i) {},
        // Get the vertical position in the element page
        pageY: function(element) {},
        // Bind events
        on: function(element, type, fn) {},
        // The window is not bound to the resize event and scroll event
        bindEvent: function() {}}// Expose plug-in objects to global objects (for compatibility)
    _global = (function() {
        return this| | -0.eval) ('this'); } ());// // finds the current scope, which refers to this, and finds the top-level object;
    if (typeof module! = ="undefined" && module.exports) {
        module.exports = Lazyload;
    } else if (typeof define === "function" && define.amd) {
        define(function() {
            return Lazyload;
        });
    } else {
        !('Lazyload' in _global) && (_global.Lazyload = Lazyload);
    }
}());
Copy the code

Now that we have a framework for lazy image loading, let’s implement each method together

Gets the picture inside the container

The important thing to note about the getImgs method that gets the images in the container is that it needs to be converted to an array in order to manipulate the collection of images (like arrays) it gets

getImgs: function() {
    // A new array container
    var arr = [];
    // Get all the IMG tags
    var imgs = this.container.getElementsByTagName('img');
    // Convert image to Array (IE: array.prototype. slice)
    for (var i = 0, len = imgs.length; i < len; i++) {
        arr.push(imgs[i]);
    }
    return arr;
}
Copy the code

Loading pictures

For the loading image update method, each image element needs to be iterated over, loaded and cleared from the image cache if it is in the viewable area

update: function() {
    if (!this.imgs.length) return;
    var i = this.imgs.length;
    while (--i >= 0) {
        // If the image is in viewable area
        if (this.shouldShow(i)) {
            this.imgs[i].src = this.imgs[i].getAttribute('data-src');
            // Clear the image cache
            this.imgs.splice(i, 1); }}}Copy the code

Filter images to load

ShouldShow (); shouldShow (); shouldShow (); The bottom height of the image is greater than the top height of the visual view and the bottom height of the image is less than the bottom height of the visual view, or the top height of the image is greater than the top height of the visual view and the bottom height of the image is less than the bottom height of the visual view

shouldShow: function(i) {
    // Get the current image
    var img = this.imgs[i],
        // View top height (scroll bar top value)
        scrollTop = document.documentElenment.scrollTop || document.body.scrollTop,
        // View the bottom height
        scrollBottom = scrollTop + document.documentElement.clientHeight,
        // Image top height
        imgTop = this.pageY(img),
        // The bottom height of the image
        imgBottom = imgTop + img.offsetHeight;
    if (imgBottom > scrollBottom && imgBottom < scrollTop || (imgTop > scrollTop && imgTop < scrollBottom)) {
        return true
    }
    return false
}
Copy the code

Gets the ordinate of the picture

The pageY method for obtaining the vertical coordinate of the image element is obtained by traversing the parent element level by level and summing up the offsetHeight of each level

pageY: function(element) {
    if (element.offsetParent) {
        return element.offsetHeight + this.pageY(element.offsetParent);
    } else {
        return element.offsetHeight
    }
}
Copy the code

The binding event

// Bind events
on: function(element, type, fn) {
        if (element.addEventListener) {
            element.addEventListener(type, fn, false)}else if (element.attachEvent) {
            element.attachEvent('on' + type, fn, false)}else {
            element['on' + type] = fn
        }
    },
    // The window is not bound to the resize event and scroll event
    bindEvent: function() {
        var that = this;
        this.on(window.'resize'.function() {
            throttle(that.update, {
                context: that,
                time: 300})})this.on(window.'scroll'.function() {
            throttle(that.update, {
                context: that,
                time: 300})})}Copy the code

The last method bindEvent binding event is to monitor the scroll and REsize events of the page. In order to detect the last execution of the event in each interaction, throttling is required for the event callback function

/ / throttling
var throttle = function() {
    // Get the first argument
    var isClear = arguments[0],
        fn;
    // If the first argument is of type Boolean then the first argument indicates whether to clear the timer
    if (typeof isClear === 'boolean') {
        // The second argument is a function
        fn = arguments[1];
        // The function timer handle exists, which is clear about the timer
        fn._throttleID && clearTimeout(fn._throttleID);
        // Delay the execution of the function with a timer
    } else {
        // The first argument is a function
        fn = isClear;
        // The second argument is the argument to function execution
        var param = arguments[1];
        // Use the default values for the parameters at run time
        var p = extend({
            context: null.args: [].time: 300
        }, param, true);
        // Clear the timer handle to execute the function
        arguments.callee(true, fn)
        // throttle(true, fn);
        // Bind a timer handle to the function to delay execution of the function
        fn._throttleID = setTimeout(function() {
            // Execute the function
            fn.apply(p.context, p.args)
        }, p.time)
    }
}
Copy the code

use

// Lazy loading of images in container
new LazyLoad('container');
Copy the code

Here is an example of LazyLoad (source code)