前言
懒加载,顾名思义,在当前网页,滑动页面到能看到图片的时候再加载图片
故问题拆分成两个:
1.如何判断图片出现在了当前视口 (即如何判断我们能够看到图片)
2.如何控制图片的加载
方案一
这是最常见的老办法:直接贴代码
核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| function lazyLoad(params, callback) { const wHeight = document.documentElement.clientHeight || document.body.clientHeight let sTop const attr = params.attr || 'data-src' const className = params.className || 'lazy' const errorImage = params.errorImage || '' const space = params.interval || 100 const dom = document.getElementsByClassName(className) let before = 0 function loadImage(el) { el.src = el.getAttribute(attr) el.removeAttribute(attr) el.onerror = function () { el.src = errorImage } } function judgeImages() { const now = Date.now() if (now - before < space) return before = now sTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop for(var j=0;j<dom.length;j++){ if(dom[j].offsetTop <= sTop + wHeight && dom[j].getAttribute(attr)){ loadImage(dom[j]) } } } judgeImages() window.addEventListener('scroll', judgeImages) } lazyLoad({ attr: 'data-src', className: 'lazy', interval: '100', errorImage: 'imgs/6.png' })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| <!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> </head> <body> <ul class="photos"> <li>1:<img class="lazy" src="imgs/6.png" data-src="imgs/1.png"></li> <li>2:<img class="lazy" src="imgs/6.png" data-src="imgs/2.png"></li> <li>3:<img class="lazy" src="imgs/6.png" data-src="imgs/3.png"></li> <li>4:<img class="lazy" src="imgs/6.png" data-src="imgs/4.png"></li> <li>5:<img class="lazy" src="imgs/6.png" data-src="imgs/5.png"></li> </ul> </body> <script type="text/javascript"> function lazyLoad(params, callback) { const wHeight = document.documentElement.clientHeight || document.body.clientHeight //浏览器的高度 let sTop //滚动条的高度 const attr = params.attr || 'data-src' const className = params.className || 'lazy' const errorImage = params.errorImage || '' const space = params.interval || 100 /** 函数节流间隔 */ const dom = document.getElementsByClassName(className) let before = 0 /** 上一次代码执行时间(节流用) */ function loadImage(el) { el.src = el.getAttribute(attr) el.removeAttribute(attr) // 图片加载失败 el.onerror = function () { el.src = errorImage } } function judgeImages() { const now = Date.now() if (now - before < space) return before = now sTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop for(var j=0;j<dom.length;j++){ if(dom[j].offsetTop <= sTop + wHeight && dom[j].getAttribute(attr)){ loadImage(dom[j]) } } } judgeImages() window.addEventListener('scroll', judgeImages) } lazyLoad({ attr: 'data-src', className: 'lazy', interval: '100', errorImage: 'imgs/6.png' }) </script> </html>
|
方法二
rootBounds 是在根元素(默认就是viewport)矩形区域的信息,调用getBoundingClientRect()的返回值;
boundingClientRect 是在目标元素(默认就是viewport),矩形区域的信息,调用getBoundingClientRect()的返回值;
intersectionRect 是目标元素与根元素交叉区域的信息,并且能清楚地告诉你目标元素的哪个部分是可见的。
intersectionRatio 目标元素的可见比例,密切相关的一个东西,它能告诉你元素当中有多大一部分是可见的(下图)。有了这个信息,你可以有效地实现一些功能,比如当资源在屏幕上可见之前刚好加载出来。
1 2 3 4 5 6 7 8 9
| // api var io = new IntersectionObserver(callback, option);
// 开始观察 io.observe(document.getElementById('example')); // 停止观察 io.unobserve(element); // 关闭观察器 io.disconnect();
|
api具体介绍链接: http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html
代码运行思路:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <!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> <script type="text/javascript" src="http://code.jquery.com/jquery-3.4.1.js"></script> </head> <style> body{ height: 1000px; } .div{ width: 300px; height: 300px; margin-bottom: 10px; border: 1px solid #dddddd; } </style> <body> <div class="div">1</div> <div class="div">2</div> <div class="div">3</div> <div class="div">4</div> <div class="div">5</div> </body> <script> $(function(){ const observer = new IntersectionObserver((changes) => { // changes: 目标元素集合 changes.forEach((change) => { if (change.isIntersecting) { // entry.intersectionRatio > 0 && entry.intersectionRatio <= 1 (intersectionRatio 表示相交区域和目标元素的比例值) const div = change.target console.log('div', div, change.intersectionRatio, change.boundingClientRect) observer.unobserve(div) // 图片已加载, 解除观察 } }) }) let divs = document.querySelectorAll('.div') divs.forEach(div => { observer.observe(div) }) }) </script> </html>
|
方法三
浏览器觉得懒加载这事可以交给自己做,你们开发者加个属性就好了。实在是…!
1
| <img src="aaa.jpg" loading="lazy">
|
不过目前浏览器兼容性不太好