图片预加载、懒加载(延迟加载)
一:预加载:就是事先把网页的图片加载到本地,之后就直接到缓存那里拿图片了。
预加载分为有序加载和无序加载两种。
原网站(https://juejin.im/entry/59d79e95f265da066e176803)
1、原生js实现
1)有序加载(原生js代码)
var imgs=[ 'http://pic1.win4000.com/wallpaper/9/579c3fbaa2918.jpg', 'http://img.tuku.cn/file_big/201404/7214f32de01b4fd8b0872522ead3480b.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396494524&di=9dab7ea72080994182b4e0f748c65091&imgtype=0&src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1501%2F13%2Fc0%2F1823997_1421130296700.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396544706&di=7b83b4ba4b6b4952a076bcb701a54d77&imgtype=jpg&src=http%3A%2F%2Fimg1.imgtn.bdimg.com%2Fit%2Fu%3D3804939088%2C891611583%26fm%3D214%26gp%3D0.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396494761&di=b34fdf8f57cd2df851f4a38dbea91035&imgtype=0&src=http%3A%2F%2Fpic.5442.com%2F2013%2F0504%2F02%2F10.jpg' ]; let len = imgs.length; /** * 遍历imgs数组,将所有图片加载出来 * 可以通过控制台查看网络请求,会发现所有图片均已加载 */ for (let i = 0; i < len; i++) { let imgObj = new Image(); // 创建图片对象 imgObj.src = imgs[i]; imgObj.addEventListener('load', function () { // 这里没有考虑error,实际上要考虑 console.log('imgs' + i + '加载完毕'); }, false); }
2)有序加载(原生js代码):
let len = imgs.length; /** * 遍历imgs数组,有序将所有图片加载出来 * 可以通过控制台查看网络请求,会发现所有图片均按顺序加载 */ let count = 0; load(); function load() { var imgObj = new Image(); imgObj.src = imgs[count]; $(imgObj).on('load error', function () { // 没错我使用了jQuery console.log(count); if (count >= len) { console.log('加载完毕'); $('.container').addClass('active'); } else { load(); // 继续加载下一张 } count++; }); }
2、jquery代码:(已经封装成插件)
/** * Created by WEIWEI on 2017/10/10. */ (function($){ function Preload(imgs,options){ // 定义 this.imgs = (typeof imgs === 'string')?[imgs]:imgs;//保证imgs为数组 this.opts = $.extend({},Preload.DEFAULTS,options)//用options去覆盖默认值 // 调用加载方法 if(this.opts.order == "ordered"){//有序加载 this._orderedLoad(); }else { this._unOrdered();//无序加载 } // Preload的默认值 Preload.DEFAULTS = { order:"ordered",//默认有序加载 each:null,//每张图片加载完成后调用此方法 all:null//图片加载完毕调用此方法 }; } // 有序加载 Preload.prototype._orderedLoad = function(){ var imgs = this.imgs; var opts = this.opts; var count = 0; var len = imgs.length; function load(){ var imgObj = new Image(); imgObj.src = imgs[count]; $(imgObj).on("load error",function(){ if(count > len-1){ opts.all && opts.all();//全部加载完成 }else { opts.each && opts.each(count); load(); } count ++ ; }) } load(); }; // 无需加载 Preload.prototype._unOrdered = function(){ var imgs = this.imgs; var opts = this.opts; var count = 0; // 计数器 var len = imgs.length; console.log("无序加载") $.each(imgs, function (index, src) { if (typeof src != 'string') { // src路径不是字符串则不往下执行 console.error('请传入字符串形式的图片路径'); return; } var imgObj = new Image(); imgObj.src = src; $(imgObj).on('load error', function () { opts.each && opts.each(count); // 首先判断each属性是否存在,存在则执行 if (count >= len -1) { opts.all && opts.all(); // 同理,不过是在图片加载完成之后调用 } count++; }); }); }; // 挂载到jQuery对象上 $.extend({ preload: function (imgs, opts) { // 命名为preload new Preload(imgs, opts); } }); })(jQuery);
<script> var imgs=[ 'http://pic1.win4000.com/wallpaper/9/579c3fbaa2918.jpg', 'http://img.tuku.cn/file_big/201404/7214f32de01b4fd8b0872522ead3480b.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396494524&di=9dab7ea72080994182b4e0f748c65091&imgtype=0&src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1501%2F13%2Fc0%2F1823997_1421130296700.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396544706&di=7b83b4ba4b6b4952a076bcb701a54d77&imgtype=jpg&src=http%3A%2F%2Fimg1.imgtn.bdimg.com%2Fit%2Fu%3D3804939088%2C891611583%26fm%3D214%26gp%3D0.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396494761&di=b34fdf8f57cd2df851f4a38dbea91035&imgtype=0&src=http%3A%2F%2Fpic.5442.com%2F2013%2F0504%2F02%2F10.jpg' ]; $.preload(imgs, { order: 'unordered', each: function (count) { console.log('正在加载第' + (count + 1) + '张图片'); }, all: function () { console.log('全部加载完成'); } }); </script>
二:懒加载(就是延时加载)
当图片出现在可视化窗口之后,图片才加载到本地。
原网站(https://juejin.im/post/59cb634a6fb9a00a4843bea9)
懒加载原理
<img>
标签有一个属性是src
,用来表示图像的URL,当这个属性的值不为空时,浏览器就会根据这个值发送请求。如果没有src
属性,就不会发送请求。
我先不设置src
,需要的时候再设置?
nice,就是这样。
我们先不给<img>
设置src
,把图片真正的URL放在另一个属性data-src
中,在需要的时候也就是图片进入可视区域的之前,将URL取出放到src
中。
重点是 ↓,
获取图片是否在可视区的三个方法:
方法一
网上看到好多这种方法,稍微记录一下。
- 通过
document.documentElement.clientHeight
获取屏幕可视窗口高度 - 通过
element.offsetTop
获取元素相对于文档顶部的距离 - 通过
document.documentElement.scrollTop
获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离
然后判断②-③<①是否成立,如果成立,元素就在可视区域内。
方法二 getBoundingClientRect
function isInSight(el) { const bound = el.getBoundingClientRect(); const clientHeight = window.innerHeight; //如果只考虑向下滚动加载 //const clientWidth = window.innerWeight; return bound.top <= clientHeight + 100; }
方法三 IntersectionObserver
先附上链接:
jjc大大:github.com/justjavac/t…
阮一峰大大:www.ruanyifeng.com/blog/2016/1…
这个方法更好,上下划懒加载图片更加顺畅。
html代码
<div class="container"> <div class="img-area"> <img class="my-photo" alt="loading" data-src="./img/img1.png"> </div> <div class="img-area"> <img class="my-photo" alt="loading" data-src="./img/img2.png"> </div> <div class="img-area"> <img class="my-photo" alt="loading" data-src="./img/img3.png"> </div> <div class="img-area"> <img class="my-photo" alt="loading" data-src="./img/img4.png"> </div> <div class="img-area"> <img class="my-photo" alt="loading" data-src="./img/img5.png"> </div> </div>
js代码(方法三)
function checkImgs() { const imgs = Array.from(document.querySelectorAll(".my-photo")); imgs.forEach(item => io.observe(item)); } function loadImg(el) { if (!el.src) { const source = el.dataset.src; el.src = source; } } const io = new IntersectionObserver(ioes => { ioes.forEach(ioe => { console.log(ioe) const el = ioe.target; const intersectionRatio = ioe.intersectionRatio; if (intersectionRatio > 0 && intersectionRatio <= 1) { loadImg(el); } el.onload = el.onerror = () => io.unobserve(el); }); });
源代码:传送门