Zhengzhou flood in July this year, the epidemic in August, the company moved in December, after the New Year’s day is the epidemic! Really not easy! This is not now the company Intranet, at home do not let the company computer, so can not write the company code at home! Whether studying at home will pay is unknown! And by the way,

1. The meaning of image lazy loading

Image delay loading is a very important performance optimization method in real projects. If you don’t do the time delay of loading images, that also page rendering time, as well as the image resource requests, rendering is done, it will hinder the page rendering progress, for the first time to load the page is slow, lazy loading can feed page loading speed on one hand, on the other hand can reduce unnecessary network consumption

** The image area is occupied by the default background image (background color) before the actual image is loaded

** First screen: ** First load other data on the first screen and wait for other data to be loaded before loading the real picture

Other screens: Scroll to the corresponding area (once on the screen, half out, completely on the screen) before loading the real image

2. Image lazy loading scheme 1

During the browser scroll bar (page scrolling), while waiting for the image to fully appear in the visible window, we load the actual image, “This is a non-first screen image

Calculate the distance A from the bottom of the box to the top of the body and compare it with the distance B from the bottom of the browser to the top of the body. If A<=B, we can load the image

WechatIMG174

<! DOCTYPEhtml>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<style>
    * {
        margin0;
    }

    .imageLazyBox {
        width236px;
        height420px;
        backgroundurl(./images/loading.gif) no-repeat center center #eee;
        background-size100px 100px;
        margin1000px 0px;

    }

    .imageLazyBox img {
        width100%;
        height100%;
        /* Start image hiding: Because in Internet Explorer, if the SRC is empty or the image is loaded incorrectly, the image is not hidden, it will show an X effect, so it is better to hide the image before it is loaded. After loading the actual image, you need to tell it to display:blok; In this way, the backflow resink of DOM is triggered, and performance consumption is relatively large. transition:opacity: .3s; -> Recommended scheme: on the one hand, after loading the real picture, we only need to set opacity:1; This, on the one hand, does not cause dom backflow and reaggregation, and on the other hand, cSS3 can achieve the effect of asymptotic */
        opacity0;
        transition: opacity 1s;
        /* display: none; * /
    }
</style>

<body>
    <div class="imageLazyBox">
        <img src="" alt="" lazy-image="./images/img1.jpeg">
    </div>
</body>


</html>
<script>
   // Image lazy loading method processing
    function imageLazyFun(imageLazyBox{
        let imageItem = imageLazyBox.querySelector('img'),
            lazy_image = imageItem.getAttribute('lazy-image')
        imageItem.src = lazy_image
        imageItem.onload = function ({
            imageItem.style.opacity = 1
        }
        imageItem.removeAttribute('lazy-image');
        imageItem.isLoad = true;

    }
    
    let imageLazyBox = document.querySelector(".imageLazyBox"),
    imageItem = imageLazyBox.querySelector('img'),
        HTML = document.documentElement;
    // Get the distance of an element from the top of the body
    function offset(element{
        let l = element.offsetLeft,
            t = element.offsetTop,
            p = element.offsetParent;
        while(p && p.tagName ! = ='body') {
            if (!/MSIE 8/.test(navigator.userAgent)) {
                l += p.clientLeft;
                t += p.clientTop;
            }
            l += p.offsetLeft;
            t += p.offsetTop;
            p = p.offsetParent;
        }
        return {
            top: t,
            left: l
        }
    }
  // Intercepting function
   let throttle = function throttle(fn, wait{
        let timeout = null.// Timer variable
            result = null.// Result of last execution
            previous = 0// The time of the last execution
        return function anymouse(. args{
            let now = new Date,
                context = this;
            let remaining = wait - (now - previous);
            // There is no time to clear the content of the last execution
            // console.log("Shiji",remaining);
            if (remaining <= 0) {
                clearTimeout(timeout);
                previous = now;
                result = fn.apply(context, args);
                // First execution
            } else if(! timeout) { timeout =setTimeout(() = > {
                    previous = new Date;
                    result = fn.apply(context, args)
                }, wait)
            }
            // console.log(result)
            return result
        }
    }
    // The execution frequency is too high to do the function interception
    window.onscroll = throttle(function ({
        console.log("Well, I did a flow stopper.")
        if (imageItem.isLoad) return
        let A = offset(imageLazyBox).top + imageLazyBox.offsetHeight,
            B = HTML.clientHeight + HTML.scrollTop;
        if (A <= B) {
            console.log("ok") imageLazyFun(imageLazyBox); }},500</script>
Copy the code

3. Image lazy loading scheme 2 using getBoundingClientRect ()

GetBoundingClientRect is used to get the set of positions of an element relative to the view. The set has properties like top, right, bottom, and left.

All you need to do is change the criteria

  window.onscroll = throttle(function ({
        console.log("Well, I did a flow stopper.")
        if (imageItem.isLoad) return
        // let A = offset(imageLazyBox).top + imageLazyBox.offsetHeight,
        // B = HTML.clientHeight + HTML.scrollTop;
        let A = imageLazyBox.getBoundingClientRect().bottom;
        B = HTML.clientHeight 
        if (A <= B) {
            console.log("ok") imageLazyFun(imageLazyBox); }},500Copy the code

4. Scheme three realizes delayed loading based on IntersectionObserver

concept

The IntersectionObserver interface (which is part of the IntersectionObserver API) provides developers with a way to asynchronously monitor the intersectionstate of a target element with its ancestors or viewports. Ancestor elements and viewports are called roots.

This is an official concept on MDN, and it looks professional to post it

Important: the way to monitor the cross state of the target element with its ancestor or window is to see if an element is visible in the window. **

API

var io = new IntersectionObserver(callback, options)
Copy the code

It’s a simple constructor.

The above code returns an instance of IntersectionObserver, callback is the callback function when the visibility of the element changes, and Options are some configuration items (optional).

options

root

The root element for viewing, which is the browser viewport by default, can also be specified as a specific element, which must be a child of the specified element

threshold

An array that specifies the crossover ratio and determines when to trigger the callback function. The default is [0].

const options = {
    rootnull.threshold: [0.0.5.1]}var io = new IntersectionObserver(callback, options)
io.observe(document.querySelector('img'))
Copy the code

rootMargin

To increase or decrease the size of the window, use the CSS definition method with the top, right, bottom and left values at 10px, 10px, 30px and 20px

Const options = {root: document.querySelector('.box'), threshold: [0, 0.5, 1], rootMargin: '30px 100px 20px'}Copy the code

Let’s look at the picture for the sake of understanding

First of all, what is the blue line? It is the root element we defined. We added the rootMargin property to make the window larger. The dashed line is the window now, so the element is now inside the window.

Thus, the root element is an absolute window only when rootMargin is empty.

Having said simple options, let’s look at callback.

callback

The callback function fires twice, both when the element enters the window (when it becomes visible) and when it leaves the window (when it becomes invisible)

Var IO = new IntersectionObserver((entries)=>{console.log(entries)}) IO. Observe ($0) // Observe the DOMCopy the code

The result is as follows

We can see a entries callback function parameters, it is a IntersectionObserverEntry array of objects, and then we focused on the IntersectionObserverEntry object

IntersectionObserverEntry

IntersectionObserverEntry observation elements of information, there are seven attributes.

BoundingClientRect obtains the result of the rectangle information of the target element based on getBoundingClientRect(), which obtains the result intersectionRatio value of the intersecting area and target element Less than or equal to zero when intersectionRect/boundingClientRect not visible intersectionRect target element and rectangular information window (root) intersect Can be referred to as regional intersection isIntersecting target element is currently visible The Boolean value is shown as true rootBounds rectangle of the root element, which is not specified to be the rectangle of the current viewport. Target The target element to observe. Time Returns a timestamp from the time of IntersectionObserver to the time when IntersectionObserver is triggered

Key points: intersectionRatio and isIntersecting are used to judge whether elements are visible.

Trigger time of IntersectionObserver

Default: once when the DOM is first listened on, once when the element appears on the page, and once when the element disappears completely

<! DOCTYPEhtml>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<style>
    * {
        margin0;
    }

    .imageLazyBox {
        width236px;
        height420px;
        backgroundurl(./images/loading.gif) no-repeat center center #eee;
        background-size100px 100px;
        margin1000px 0px;

    }

    .imageLazyBox img {
        width100%;
        height100%;
        /* Start image hiding: Because in Internet Explorer, if the SRC is empty or the image is loaded incorrectly, the image is not hidden, it will show an X effect, so it is better to hide the image before it is loaded. After loading the actual image, you need to tell it to display:blok; In this way, the backflow resink of DOM is triggered, and performance consumption is relatively large. transition:opacity: .3s; -> Recommended scheme: on the one hand, after loading the real picture, we only need to set opacity:1; This, on the one hand, does not cause dom backflow and reaggregation, and on the other hand, cSS3 can achieve the effect of asymptotic */
        opacity0;
        transition: opacity 1s;
        /* display: none; * /
    }
</style>
<body>
    <div class="imageLazyBox">
        <img src="" alt="" lazy-image="./images/img1.jpeg">
    </div>
</body>
</html>
<script>

    function imageLazyFun(imageLazyBox{
        let imageItem = imageLazyBox.querySelector('img'),
            lazy_image = imageItem.getAttribute('lazy-image')
        imageItem.src = lazy_image
        imageItem.onload = function ({
            imageItem.style.opacity = 1
        }
        imageItem.removeAttribute('lazy-image');
        imageItem.isLoad = true;
    }

    let imageLazyBox = document.querySelector(".imageLazyBox");
    let ob = new IntersectionObserver(changes= > {
        // Cross information between the DOM element we are listening for and the visual window
        let item = changes[0];
        target = item.target;
        // The box is fully in the viewport
        if (item.isIntersecting) {
            // The box is fully in the viewport
            imageLazyFun(target);
            // This element is loaded lazily once, and then no longer needs to be listened for
            ob.unobserve(target)

        }
    });
    // Listen for dom elements
    ob.observe(imageLazyBox)
    // Remove the listener
    // ob.unobserve(imageLazyBox)



</script>
Copy the code

5. There are four schemes for delayed image loading, but future methods are incompatible

Loading =”lazy” browsers are less compatible

Browser compatibility query url


<div class="imageLazyBox">
        <img src="./images/img1.jpeg"  loading="lazy" >
    </div>
Copy the code

6. Comparison of advantages and disadvantages of several image lazy loading methods

GetBoundingClientRect has less computation than the first method, but getBoundingClientRect is not compatible and the first method is suitable for mobile terminal, both of which use window.onscroll method, so you need to write your own intercepting function to optimize performance

Compared with the window.onscroll method, IntersectionObserver is more convenient and has better performance and does not need its own throttling processing