(可视区域加载)图片懒加载实现原理

Posted 最骚的就是你

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(可视区域加载)图片懒加载实现原理相关的知识,希望对你有一定的参考价值。

参考文章:http://www.cnblogs.com/xiaohuochai/p/4859485.html

               http://www.cnblogs.com/xiaohuochai/p/4859899.html

                    http://www.cnblogs.com/vajoy/p/4263291.html

定义

  图片延迟加载也称为懒加载,延迟加载图片或符合某些条件时才加载某些图片,通常用于图片比较多的网页。可以减少请求数或者延迟请求数,优化性能。

 

呈现形式

【1】延时加载,使用setTimeout或setInterval进行加载延迟,如果用户在加载前就离开,自然就不会进行加载。
【2】条件加载,符合某些条件或者触发了某些条件才开始异步加载。
【3】可视区域加载,仅仅加载用户可以看到的区域,这个主要监控滚动条来实现,一般距离用户看到的底边很近的时候开始加载,这样能保证用户下拉时图片正好接上,不会有太长时间的停顿。

 

基本步骤

【1】网页中的图片都设为同一张图片
【2】给图片增加data-original = "img/test.jpg"的属性,保存图片的真实地址
【3】当触发某些条件时,自动改变该区域的图片的src属性为真实的地址

 

应用

【点击按钮显示图片】

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{
    margin: 0;
}
img{
    height: 100px;
    width: 100px;
}
</style>
</head>
<body>
<button>加载图片</button>
<img src="#" alt="测试" data-original = "img/test.png">
<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
var oImg = document.images[0];    
oBtn.onclick = function(){
    oImg.src = "img/loading.gif";
    if(oImg.dataset){
        aftLoadImg(oImg,oImg.dataset.original);    
    }else{
        aftLoadImg(oImg,oImg.getAttribute("data-original"));
    }
}
function aftLoadImg(obj,url){
    var oImg = new Image();
    oImg.onload = function(){
        obj.src = oImg.src;
    }
    oImg.src = url;
}
</script>    
</body>
</html>
复制代码

 

【可视区显示图片】

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{
    margin: 0;
}
ul{
    margin: 0;
    padding: 0;
    list-style: none;
}
img{
    border: none;
    vertical-align: middle;
}
.in{
    border: 1px solid black;
    margin: 10px;
    text-align: center;
    height: 400px;
    width: 400px;
    float: left;
}
.in img{
    height: 400px;
    width: 400px;
}
</style>
</head>
<body>
<ul class="list">
    <li class="in"><img src="img/loading.gif" alt="测试" data-original = "img/img1.gif"></li>
    <li class="in"><img src="img/loading.gif" alt="测试" data-original = "img/img2.gif"></li>
    <li class="in"><img src="img/loading.gif" alt="测试" data-original = "img/img3.gif"></li>
    <li class="in"><img src="img/loading.gif" alt="测试" data-original = "img/img4.gif"></li>    
    <li class="in"><img src="img/loading.gif" alt="测试" data-original = "img/img1.gif"></li>
    <li class="in"><img src="img/loading.gif" alt="测试" data-original = "img/img2.gif"></li>
    <li class="in"><img src="img/loading.gif" alt="测试" data-original = "img/img3.gif"></li>
    <li class="in"><img src="img/loading.gif" alt="测试" data-original = "img/img4.gif"></li>                           
</ul>

<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
var aImages = document.images;
loadImg(aImages);
window.onscroll = function(){
    loadImg(aImages);
};
function loadImg(arr){
    for( var i = 0,len = arr.length; i < len; i++){
        if(arr[i].getBoundingClientRect().top < document.documentElement.clientHeight && !arr[i].isLoad){
            arr[i].isLoad = true;
            arr[i].style.cssText = "transition: \'\'; opacity: 0;"
            if(arr[i].dataset){
                aftLoadImg(arr[i],arr[i].dataset.original);    
            }else{
                aftLoadImg(arr[i],arr[i].getAttribute("data-original"));
            }
            (function(i){
                setTimeout(function(){
                    arr[i].style.cssText = "transition: 1s; opacity: 1;"
                },16)
            })(i);
        }
    }
}
function aftLoadImg(obj,url){
    var oImg = new Image();
    oImg.onload = function(){
        obj.src = oImg.src;
    }
    oImg.src = url;
}

</script>    
</body>
</html>
复制代码

 

【效果展示】

 

好的代码像粥一样,都是用时间熬出来的
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

图片预加载

 

定义

  预加载图片是提升用户体验的一个好办法,提前加载用户所需的图片,保证图片快速、无缝发布,使用户在浏览器网站时获得更好用户体验。常用于图片画廊等应用中。
  [注意]若使用即时加载,加载的图片与页面的其他内容一起加载会增加页面的整体加载时间,所以使用window.onload比较合适。

 

两种思路

【使用背景图像】
  使用页面无用元素的背景图片预加载

复制代码
<style>
body{
    margin: 0;
}
img{
    width: 100px;
    height: 100px;
}
ul{
    margin: 0;
    padding: 0;
    list-style: none;
}
.list li{
    height: 0;
    width: 0;
}
</style>
</head>
<body>
<button>载入图片</button>
<img src="img/test.png" alt="测试">
<ul class="list">
    <li id="preload1"></li>
    <li id="preload2"></li>
    <li id="preload3"></li>
    <li id="preload4"></li>
</ul>
<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
var oImg0 = document.images[0];
var array = ["img/img1.gif","img/img2.gif","img/img3.gif","img/img4.gif"]
var iNow = -1;
oBtn.onclick = function(){
    iNow++;
    iNow = iNow%4;
    oImg0.src = array[iNow];
}
function preLoadImg(){
    preload1.style.background = "url(\'img/img1.gif\')";
    preload2.style.background = "url(\'img/img2.gif\')";
    preload3.style.background = "url(\'img/img3.gif\')";
    preload4.style.background = "url(\'img/img4.gif\')";
}
window.onload = function(){
    preLoadImg();    
}
</script>
</body>
复制代码

 

【使用Image()】
  通过new Image()或document.createElement(\'img\')创建<img>标签,然后通过<img>src赋值语句来加载图片

复制代码
<style>
body{
    margin: 0;
}
img{
    width: 100px;
    height: 100px;
}
</style>
</head>
<body>
<button>载入图片</button>
<img src="img/test.png" alt="测试">
<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
var oImg0 = document.images[0];
var array = ["img/img1.gif","img/img2.gif","img/img3.gif","img/img4.gif"]
var iNow = -1;
oBtn.onclick = function(){
    iNow++;
    iNow = iNow%4;
    oImg0.src = array[iNow];
}
var aImages = [];
function preLoadImg(array){
    for(var i = 0, len = preLoadImg.arguments[0].length; i < len; i++){
        aImages[i] = new Image();
        aImages[i].src = preLoadImg.arguments[0][i];
    }
}
window.onload = function(){
    preLoadImg(array);    
}
</script>
</body>
复制代码

 

onload事件

  利用图像的onload事件可以确切地知道图片是否被真正加载,并可能在后续执行一系列对图片的操作功能,如获取当前图片的实际宽高及索引等
  [注意1]图片的src赋值语句必须放在图片的onload事件后面。否则可能出现图片已经加载完毕、但事件绑定尚未完成的情况

复制代码
<button>载入图片</button>
<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
oBtn.onclick = function(){
    preLoadImg(\'img/test.png\');
}
function preLoadImg(url){
    var oImg = document.createElement(\'img\');
    //在本机环境下,IE8-浏览器下oImg的onload事件放在src后面将无法载入图片
    oImg.src = url;
    oImg.onload = function(){
        document.body.appendChild(oImg);
        oImg.onload = null;
        oImg = null;
    }            
}
</script>    
复制代码

  

  [注意2]Image对象的onload属性引用了一个匿名函数对象,而匿名函数通过其作用域引用Image对象,这种循环引用会有IE6中导致内存泄漏,因此,应该解除循环引用。

 

【递归写法】

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{
    margin: 0;
}
img{
    width: 100px;
    height: 100px;
}
</style>
</head>
<body>
<button>载入图片</button>
<img src="img/test.png" alt="测试">
<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
var oImg0 = document.images[0];
var array = ["img/img1.gif","img/img2.gif","img/img3.gif","img/img4.gif"]
var iNow = -1;
oBtn.onclick = function(){
    iNow++;
    iNow = iNow%4;
    oImg0.src = array[iNow];
}
var oImg = document.createElement(\'img\');
var iDown = 0;    
preLoadImg();
function preLoadImg(){
    oImg.onload = function(){
        iDown++;
        alert(\'第\' + iDown + \'张图片的宽:\' + this.width + \' 高:\' + this.height);
        if(iDown < array.length){
            preLoadImg();
        }else{
            oImg.onload = null;
            oImg = null;
        }
    }
    oImg.src = array[iDown];                        
}
</script>
</body>
</html>
复制代码

 

【考虑onerror的更完善写法】

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{
    margin: 0;
}
img{
    width: 100px;
    height: 100px;
}
</style>
</head>
<body>
<button>载入图片</button>
<img src="img/test.png" alt="测试">
<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
var oImg0 = document.images[0];
var array = ["img/img1.gif","img/img2.gif","img/img3.gif","img/img4.gif"]
var iNow = -1;
oBtn.onclick = function(){
    iNow++;
    iNow = iNow%4;
    oImg0.src = array[iNow];
}
var iDown = 0;
var oImage = new Image();
function preLoadImg(arr){
    function loadImgTest(arr){
        iDown++;
        if(iDown < arr.length){
            preLoadImg(arr);
        }else{
            alert(\'ok\');
            oImg.onload = null;
            oImg = null;            
        }
    }
    oImage.onload = function(){
        loadImgTest(arr);
    };
    oImage.onerror = function(){
        loadImgTest(arr);
    };    
    oImage.src = arr[iDown];
}
preLoadImg(array);
</script>
</body>
</html>
复制代码

 

【循环写法】

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{
    margin: 0;
}
img{
    width: 100px;
    height: 100px;
}
</style>
</head>
<body>
<button>载入图片</button>
<img src="img/test.png" alt="测试">
<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
var oImg0 = document.images[0];
var array = ["img/img1.gif","img/img2.gif","img/img3.gif","img/img4.gif"]
var iNow = -1;
oBtn.onclick = function(){
    iNow++;
    iNow = iNow%4;
    oImg0.src = array[iNow];
}
function preLoadImg(arr,callback){
    var aImages = [];
    var iDown = 0;
    for(var i = 0; i < arr.length; i++){
        aImages[i] = new Image();
        aImages[i].onload = function(){
            loadImgTest(arr,callback);
        };
        aImages[i].onerror = function(){
            loadImgTest(arr,callback);
        };        
        aImages[i].src = arr[iDown];
    }
    function loadImgTest(arr,callback){
        iDown++;
        if(iDown == arr.length){
            alert(\'ok\');
            callback && callback.call(aImages);        
        }
    }    
}
preLoadImg(array,function(){
    console.log(this[0].width);
});
</script>
</body>
</html>
复制代码

 

应用

【预加载模糊变清晰】

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{
    margin: 0;
}
img{
    width: 500px;
    height: 500px;
}
</style>
</head>
<body>
<button>载入图片</button>
<img src="#" alt="测试">
<script>
var oBtn = document.getElementsByTagName(\'button\')[0];
var oImg0 = document.images[0];
var arrayB = ["img/img1.gif","img/img2.gif","img/img3.gif","img/img4.gif"];
var arrayL = ["img/img1.jpg","img/img2.jpg","img/img3.jpg","img/img4.jpg"];
var iNow = -1;
oBtn.onclick = function(){
    iNow++;
    iNow = iNow%4;
    oImg0.src = arrayL[iNow];
    aftLoadImg(arrayB,oImg0);
}

var aImages = [];
window.onload = function(){
    preLoadImg(arrayL);    
}
function preLoadImg(arr){
    for(var i = 0, len = arr.length; i < len; i++){
        aImages[i] = new Image();
        aImages[i].src = arr[i];
    }
}
function aftLoadImg(arr,obj){
    var oImg = new Image();
    oImg.onload = function(){
        obj.src = arr[iNow];
    }
    oImg.src = arr[iNow];
}
</script>
</body>
</html>
复制代码

 【效果演示】

好的代码像粥一样,都是用时间熬出来的

以上是关于(可视区域加载)图片懒加载实现原理的主要内容,如果未能解决你的问题,请参考以下文章

原生js实现图片懒加载原理

图片懒加载小小心得

滚动加载图片(懒加载)实现原理

懒加载——实现原理

原生JS实现图片懒加载之一:Element.getBoundingClientRect()

图片懒加载和预加载