ahaow / Blog

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

懒加载与预加载

ahaow opened this issue · comments

懒加载

1.1 什么懒加载

懒加载就是延迟加载

当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,"占位图"), 只有当图片出现在浏览器的可视区域内时,才设置图片真正的路径,让图片显示出来

1.2 为什么使用懒加载

很多页面,内容很丰富,页面很长,图片较多。比如说各种商场页面,这些页面图片数量多,而且比较大,要是页面载入就一次性加载完毕,会花费很多时间

1.3 懒加载原理

页面中的img元素,如果没有src属性,浏览器就不会发出请求去下载图片,只有通过JavaScript设置了图片路径,浏览器才会发送请求

懒加载的原理就是先在页面中把所有的图片统一使用一张占位图进行占位,把真正的路径存在元素的 data-url (这个名字起个自己认识好记的就行了)属性中,要用的时候就取出来,再设置

1.4 懒加载实现步骤

  • 首先,不要将图片地址放在src属性中,而是放在其他属性(data-origin)中
  • 页面加载完成后,根据scrollTop判断图片是否在用户的视野内,如果在,则将data-original属性中的值取出来存放在src属性中
  • 在滚动事件中重复判断图片是否进入视野,如果进入,则将data-origin属性的值取出来存放在src属性中

1.5 懒加载的优点

页面加载速度快,可以减轻服务器的压力,节约了流量,用户体验好

1.6 代码

<!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>Document</title>
    <style type="text/css" media="all">
        body,
        ul,
        li {
            padding: 0;
            margin: 0;
        }

        body {
            font-size: 12px;
            -webkit-user-select: none;
            -webkit-text-size-adjust: none;
            font-family: helvetica;
        }

        .lazyLoad ul li {
            height: 200px;
            border: 1px solid red;
            margin-bottom: 2px;
            overflow: hidden;
            text-align: center;
        }
    </style>
</head>

<body>
    <div class="lazyLoad">
        <ul>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
            <li><img data-src="http://img0.imgtn.bdimg.com/it/u=2873269578,797009742&fm=26&gp=0.jpg" alt=""></li>
        </ul>
    </div>

    <script>
        
        function lazyLoad(obj, option) {
            this.init.apply(this, arguments)
        }

        lazyLoad.prototype = {
            init: function (el, param) {
                let opt = {
                    dataSrc: 'lazyImg',
                    dataImg: './11.jpg', // 占位图
                    contens: typeof el === 'string' ? this.getElement(el) : el || document.body, // 判断 el 传进来的是 dom对象 还是 string
                    cb: null 
                }

                if (param && param instanceof Object) {
                    for (let key in param) {
                        if (param.hasOwnProperty(key)) {
                            opt[key] = param[key]
                        }
                    }
                }
                this.opt = opt
                console.log(this.opt)
                this.render()
                this.bindUI()
            },
            render: function () {
                let _opt = this.opt,
                    _imgArr = [],
                    _dom = _opt.contens,
                    // 获取到传进来的dom对象 里面所有的 img 元素
                    _img = _dom.querySelectorAll('['+ _opt.dataSrc +']');
                if(_img.length) {
                    let _tagName
                    Array.prototype.forEach.call(_img,function(item,i) {
                        console.log(item.tagName);
                        _tagName = item.tagName.toLowerCase() // 将 元素 的 tagName 小写化
                        if(_tagName === 'img' && !item.getAttribute('src')) {
                            item.setAttribute('src',this.opt.dataImg); // 将img元素的src的值 设为 传进来的 占位图
                        }
                        _imgArr.push({
                            obj: item,
                            tagName: item.tagName.toLowerCase(),
                            src: item.getAttribute(_opt.dataSrc)
                        })

                    }.bind(this));
                }
                this.imgArr = _imgArr
                this.loadImg()
            },
            bindUI: function() {
                window.addEventListener('scroll',function() {
                    this.loadImg()
                }.bind(this),false)
            },
            loadImg: function() {
                let _imgArr = this.imgArr;
                let _dataSrc , _src;
                if(_imgArr.length) {
                    _imgArr.forEach(function(item,i) {
                        // console.log(item)

                        if(this.isLoad(item.obj)) {  // 判断 该图片是否进入了 可视区域
                            // 如果是图片
                            if(item.tagName === 'img') {
                                _dataSrc = this.opt.dataSrc
                                _src = item.obj.getAttribute(_dataSrc)

                                console.log(_dataSrc);
                                console.log(_src); // img 下 data-src 属性下的值

                                if(_src) {
                                    console.log(item)
                                    item.obj.setAttribute('src',_src); // 将 data-src 的值 赋值给 img 下的 src 属性中
                                    item.obj.removeAttribute(_dataSrc); // 删除 data-src 属性
                                    if(typeof this.opt.cb === 'function') {
                                        return this.opt.cb.call(this,item.obj)
                                    }
                                }
                            } else {
                                // 加载文件
                                if(typeof this.opt.cb === 'function') {
                                    if(_imgArr[i].isLoad) {
                                        return false
                                    }
                                }
                                _imgArr[i].isLoad = 1;
                                return this.opt.cb.call(this,item.obj)
                            }
                        }
                    }.bind(this))
                }
            },
            isLoad: function(img) {
                let _scrollTop = document.body.scrollTop || document.documentElement.scrollTop
                let _winHeight = window.innerHeight
                let _offsetTop = img.offsetTop
                let _height = img.offsetHeight
                if(_offsetTop + _height >= _scrollTop && _offsetTop <= _winHeight + _scrollTop) {
                    /**
                        _offsetTop + _height >= _scrollTop 
                        img图片的距离可视区域的高度 + 图片的高度 大于等于 浏览器窗口顶部与文档顶部之间的距离 也就是滚动条滚动的距离

                        _offsetTop <= _winHeight + _scrollTop
                        img图片的距离可视区域的高度 小于等于  屏幕可视窗口大小 + 浏览器窗口顶部与文档顶部之间的距离 也就是滚动条滚动的距离
                    */
                        return true
                }
                return false
            },
            getElement: function(o) {
                return document.querySelector(o)
            } 
        }

        let loadPic = function (obj, option) {
            if (!obj) return
            return new lazyLoad(obj, option)
        }
        

        var t = loadPic('.lazyLoad',{
            dataSrc : 'data-src',
            cb : function(item){
                // console.log(item)
            }
        })
    </script>
</body>
</html>

预加载

1.1 什么是预加载

提前加载图片,当用户查看时可以直接从本地缓存中渲染

1.2 为什么要使用预加载

图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度。这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速、无缝地发布,也可帮助用户在浏览你网站内容时获得更好的用户体验。

2.3 实现预加载

<!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>Document</title>
    <style>
        #preload_01 img {
            width: 100px;
            height: 100px;
            margin: 8px;
        }
    </style>
</head>

<body>
    <div id="preload_01"></div>
    <script>
        function preload() {
            let images = new Array()
            for (let i = 0; i < preload.arguments.length; i++) {
                images[i] = new Image()
                images[i].src = preload.arguments[i]
                document.getElementById('preload_01').appendChild(images[i]);
            }
        }
		// 使用addLoadEvent()函数来延迟preloader()函数的加载时间,直到页面加载完毕。
        function addLoadEvent(func) {
            var oldonload = window.onload;
            if (typeof window.onload != 'function') {
                window.onload = func;
            } else {
                window.onload = function () {
                    if (oldonload) {
                        oldonload();
                    }
                    func();
                }
            }
        }
        addLoadEvent(preload(
            "http://img4.imgtn.bdimg.com/it/u=1688026885,2773767715&fm=26&gp=0.jpg",
            "http://img4.imgtn.bdimg.com/it/u=1688026885,2773767715&fm=26&gp=0.jpg",
            "http://img4.imgtn.bdimg.com/it/u=1688026885,2773767715&fm=26&gp=0.jpg"
        ))
    </script>
</body>
</html>

懒加载和预加载的对比

  1. 概念
    1. 懒加载也叫延迟加载:js图片延迟加载,延迟加载图片或符合某些条件时才加载某些图片
    2. 预加载:提前加载图片,当用户需要查看时可以直接从本地缓冲中渲染
  2. 区别:
    1. 两种技术的本质:两者行为是相反的,一个是提前加载,一个是迟缓甚至不加载
    2. 懒加载对服务器端有一定的缓解压力,预加载则会增加服务器端压力
  3. 意义:
    1. 懒加载的主要目的是作为服务器端的优化,减少请求或延迟请求数
    2. 预加载可以说是牺牲服务器前端性能,换取更好的用户体验,这样可以使用户的操作得到最快的反映。