zoukankan      html  css  js  c++  java
  • 懒加载的3种实现方式

    优势

    1. 性能收益:浏览器加载图片、decode、渲染都需要耗费资源,懒加载能节约性能消耗,缩短onload事件时间。
    2. 节约带宽:这个不需要解释。

    通常,我们在html中展示图片,会有两种方式:

    1. img 标签
    2. css background-image

    img的懒加载实现

    img有两种方式实现懒加载:

    1. 事件监听(scroll、resize、orientationChange)
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>event</title>
        <style>
            img {
                background: #F1F1FA;
                 400px;
                height: 300px;
                display: block;
                margin: 10px auto;
                border: 0;
            }
        </style>
    </head>
    <body>
        <img src="image1.jpg?tr=w-400,h-300" />
        <img src="image2.jpg?tr=w-400,h-300" />
        <img src="image3.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image2.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image3.jpg?tr=w-400,h-300" /> -->
        <img class="lazy" src="image4.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image5.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image6.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image7.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image8.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image9.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image10.jpg?tr=w-400,h-300" />
        <script>
            document.addEventListener("DOMContentLoaded", function() {
                var lazyloadImages = document.querySelectorAll("img.lazy");    
                var lazyloadThrottleTimeout;
                
                function lazyload () {
                    if(lazyloadThrottleTimeout) {
                        clearTimeout(lazyloadThrottleTimeout);
                    }    
                    
                    lazyloadThrottleTimeout = setTimeout(function() {
                        var scrollTop = window.pageYOffset;
                        lazyloadImages.forEach(function(img) {
                            if(img.offsetTop < (window.innerHeight + scrollTop)) {
                                img.src = img.dataset.src;
                                img.classList.remove('lazy');
                            }
                        });
                        if(lazyloadImages.length == 0) {
                            document.removeEventListener("scroll", lazyload);
                            window.removeEventListener("resize", lazyload);
                            window.removeEventListener("orientationChange", lazyload);
                        }
                    }, 20);
                }
                
                document.addEventListener("scroll", lazyload);
                window.addEventListener("resize", lazyload);
                window.addEventListener("orientationChange", lazyload);
            });
        </script>
    </body>
    </html>
    
    1. Intersection Observer(兼容性问题)
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>observer</title>
        <style>
            img {
                background: #F1F1FA;
                 400px;
                height: 300px;
                display: block;
                margin: 10px auto;
                border: 0;
            }
        </style>
    </head>
    <body>
        <img src="image2.jpg?tr=w-400,h-300" />
        <img src="image3.jpg?tr=w-400,h-300" /> -->
        <img class="lazy" src="image1.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image2.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image3.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image4.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image5.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image6.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image7.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image8.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image9.jpg?tr=w-400,h-300" />
        <img class="lazy" src="image10.jpg?tr=w-400,h-300" />
        <script>
            document.addEventListener("DOMContentLoaded", function() {
                var lazyloadImages = document.querySelectorAll(".lazy");
                var imageObserver = new IntersectionObserver(function(entries, observer) {
                    entries.forEach(function(entry) {
                        if (entry.isIntersecting) {
                            var image = entry.target;
                            image.src = image.dataset.src;
                            image.classList.remove("lazy");
                            imageObserver.unobserve(image);
                        }
                    });
                });
                lazyloadImages.forEach(function(image) {
                    imageObserver.observe(image);
                });
            });
        </script>
    </body>
    </html>
    

    background-image的实现

    background-image的实现跟img的原理基本是一样的,区别是在对class的处理上:

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>background</title>
        <style>
            body {
                margin: 0;
            }
            .bg {
                height: 200px;
            }
            #bg-image.lazy {
                background-image: none;
                background-color: #F1F1FA;
            }
            #bg-image {
                background-image: url("image1.jpg?tr=w-400,h-300");
                background-size: 100%;
            }
        </style>
    </head>
    <body>
        <div id="bg-image" class="bg lazy"></div>
        <div id="bg-image" class="bg lazy"></div>
        <div id="bg-image" class="bg lazy"></div>
        <div id="bg-image" class="bg lazy"></div>
        <div id="bg-image" class="bg lazy"></div>
        <div id="bg-image" class="bg lazy"></div>
        <div id="bg-image" class="bg lazy"></div>
        <div id="bg-image" class="bg lazy"></div>
        <script>
            document.addEventListener("DOMContentLoaded", function() {
                var lazyloadImages = document.querySelectorAll(".lazy");
                var imageObserver = new IntersectionObserver(function(entries, observer) {
                    entries.forEach(function(entry) {
                        if (entry.isIntersecting) {
                            var image = entry.target;
                            image.classList.remove("lazy");
                            imageObserver.unobserve(image);
                        }
                    });
                });
                lazyloadImages.forEach(function(image) {
                    imageObserver.observe(image);
                });
            });
        </script>
    </body>
    </html>
    

    渐进式懒加载

    渐进式懒加载,指的是存在降级处理,通常html形式如下:

    
    <a href="full.jpg" class="progressive replace">
      <img src="tiny.jpg" class="preview" alt="image" />
    </a>
    

    这样的代码会有2个好处:

    1. 如果js执行失败,可以点击预览
    2. 大小与实际图一致的占位data URI,避免reflow

    最终的代码如下:

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>progressive</title>
        <style>
            a.progressive {
                position: relative;
                display: block;
                overflow: hidden;
                outline: none;
            }
            a.progressive:not(.replace) {
                cursor: default;
            }
            a.progressive img {
                display: block;
                 100%;
                max- none;
                height: auto;
                border: 0 none;
            }
            a.progressive img.preview {
                filter: blur(2vw);
                transform: scale(1.05);
            }
            a.progressive img.reveal {
                position: absolute;
                left: 0;
                top: 0;
                will-change: transform, opacity;
                animation: reveal 1s ease-out;
            }
            @keyframes reveal {
                0% {transform: scale(1.05); opacity: 0;}
                100% {transform: scale(1); opacity: 1;}
            }
        </style>
    </head>
    <body>
        <a href="nature5.jpg" data-srcset="https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature5.jpg 800w, nature5big.jpg 1600w" class="progressive replace">
            <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2NjIpLCBxdWFsaXR5ID0gNzAK/9sAQwAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7/8AAEQgABQAUAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A5yC3e2S3gM7OEQHdgA57VTuLAPqUoaUk7yM7R2BPSiivS5VN8stjmk2ldGVM3lyshG7bxk0UUV4skk2jdN2P/9k=" class="preview" alt="palm trees" />
        </a>
        <a href="nature2.jpg" class="progressive replace">
            <img src="http://lorempixel.com/20/15/nature/2/" class="preview" alt="sunset" />
        </a>
        <a href="nature3.jpg" class="progressive replace">
            <img src="http://lorempixel.com/20/15/nature/3/" class="preview" alt="tide" />
        </a>
        <a href="nature5.jpg" data-srcset="https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature5.jpg 800w, nature5big.jpg 1600w" class="progressive replace">
            <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2NjIpLCBxdWFsaXR5ID0gNzAK/9sAQwAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7/8AAEQgABQAUAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A5yC3e2S3gM7OEQHdgA57VTuLAPqUoaUk7yM7R2BPSiivS5VN8stjmk2ldGVM3lyshG7bxk0UUV4skk2jdN2P/9k=" class="preview" alt="palm trees" />
        </a>
        <a href="nature2.jpg" class="progressive replace">
            <img src="http://lorempixel.com/20/15/nature/2/" class="preview" alt="sunset" />
        </a>
        <a href="nature3.jpg" class="progressive replace">
            <img src="http://lorempixel.com/20/15/nature/3/" class="preview" alt="tide" />
        </a>
        <script>
            window.addEventListener('load', function() {
                var pItem = document.getElementsByClassName('progressive replace'), timer;
    
                window.addEventListener('scroll', scroller, false);
                window.addEventListener('resize', scroller, false);
                inView();
    
                function scroller(e) {
                    timer = timer || setTimeout(function() {
                        timer = null;
                        requestAnimationFrame(inView);
                    }, 300);
                }
    
                function inView() {
                    var scrollTop = window.pageYOffset;
                    var innerHeight = window.innerHeight;
                    var p = 0;
                    while (p < pItem.length) {
                        var offsetTop = pItem[p].offsetTop;
                        if (offsetTop < (scrollTop + innerHeight)) {
                            loadFullImage(pItem[p]);
                            pItem[p].classList.remove('replace');
                        }
                        else p++;
                    }
                }
    
    
                function loadFullImage(item) {
                    var img = new Image();
                    if (item.dataset) {
                        img.srcset = item.dataset.srcset || '';
                        img.sizes = item.dataset.sizes || '';
                    }
                    img.src = item.href;
                    img.className = 'reveal';
                    if (img.complete) addImg();
                    else img.onload = addImg;
    
                    function addImg() {
                        item.addEventListener('click', function(e) { e.preventDefault(); }, false);
                        item.appendChild(img).addEventListener('animationend', function(e) {
                            var pImg = item.querySelector('img.preview');
                            if (pImg) {
                                e.target.alt = pImg.alt || '';
                                item.removeChild(pImg);
                                e.target.classList.remove('reveal');
                            }
                        });
                    }
    
                }
    
            }, false);
        </script>
    </body>
    </html>
    

    现成库

    推荐下面这个库,使用非常简单:https://www.npmjs.com/package/lozad

    https://segmentfault.com/a/1190000017795499来源:

  • 相关阅读:
    准备重启blog。。。
    愿我成功省一。
    [LUOGU]P5502 [JSOI2015]最大公约数
    [LUOGU]P3400 仓鼠窝
    [LUOGU]P5149 会议座位
    OI退役记
    新开博客园~~
    1108 模拟赛
    牛客1102
    题解 CF21B 【Intersection】
  • 原文地址:https://www.cnblogs.com/lalalagq/p/10241711.html
Copyright © 2011-2022 走看看