实现原理
- 结构中,我们使用一个盒子包裹着图片(图片不显示的时候,可以先占据着这个位置,并且设置默认背景图或背景颜色)
- 最开始,img 的 src 设置默认背景图,并把图片真实地址放到自定义属性中(比如:data-src )
- 当 JS 监听到该图片元素进入可视窗口时,将自定义属性中的地址放到 src 属性中,达到懒加载效果
作用:
- 防止页面一次性向服务器发送大量请求,导致页面卡顿
- 全部加载会耗费大量流量
预备知识:
clientHeight
:当前盒子可视区域的高度(height+上下padding)
offsetHeight
:获取当前盒子的总高度(height+上下padding+上下border)
offsetTop
:当前盒子距离父级参照物的上偏移量
offsetParent
:当前盒子的父级参照物
scrollTop
:获取和设置当前盒子纵向滚动条卷曲的高度
代码实现
为了显示更加明显,当图片的下边框 = 浏览器可视窗口的下边框时,显示图片真实路径
- 图片下边框:图片距离 body 的上偏移量 + 图片自身的总高度
- 浏览器可视窗口下边框:浏览器滚动条卷曲高度 + 当前浏览器可视窗口的高度
单张图片懒加载
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 58 59 60 61 62 63 64 65 66
| <!DOCTYPE html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>单张图片延时加载</title> <style> * { margin: 0; padding: 0; } img { width: 100%; height: 100%; } #box { width: 300px; height: 200px; margin: 800px auto; } </style> </head>
<body> <div id="box"> <img src="img/default.jpg" true-img="img/1.jpg" alt="" /> </div> </body> <script src="utils.js"></script> <script> let box = document.getElementById("box"); let img = document.getElementsByTagName("img")[0]; function check() { if (img.flag) { return; } let boxH = box.offsetHeight; let boxT = utils.offset(box).top; let winH = utils.win("clientHeight"); let winT = utils.win("scrollTop"); if (winH + winT >= boxH + boxT) { let newImg = new Image(); let trueImg = img.getAttribute("true-img"); newImg.src = trueImg; newImg.onload = function () { img.src = trueImg; img.flag = true; newImg = null; }; newImg.onerror = function () { img.src = "img/2.jpg"; img.flag = true; }; } } window.onscroll = check; </script> </html>
|
多张图片懒加载
这里使用 getElementsByClassName
,这个具有映射关系,下面简单介绍一下这个映射关系:
getElementsByClassName
返回对象是动态的 HTMLCollection
1 2 3 4 5 6 7 8 9 10 11 12 13
| <ul id="lists"> <li class="bg">1</li> <li>2</li> <li>3</li> <li id="end">4</li> </ul> <script> var lis = document.getElementsByTagName("li"); lis[0].classList.remove("bg"); lists.removeChild(end); console.log(lis.length); console.log(lis[0].classList); </script>
|
uerySelectorAll
返回对象是静态 NodeList
1 2 3 4 5 6 7 8 9 10 11 12 13
| <ul id="lists"> <li class="bg">1</li> <li>2</li> <li>3</li> <li id="end">4</li> </ul> <script> var lis = document.querySelectorAll("li"); lis[0].classList.remove("bg"); lists.removeChild(end); console.log(lis.length); console.log(lis[0].classList); </script>
|
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 58 59 60 61 62 63 64 65 66 67
| <!DOCTYPE html>
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .box { margin: 500px auto; } .box img { display: block; margin: auto; margin-bottom: 10px; height: 200px; } </style> </head>
<body> <div class="box"> <img src="img/default.jpg" class="bg" true-img="img/1.jpg" alt=""> <img src="img/default.jpg" class="bg" true-img="img/2.jpg" alt=""> <img src="img/default.jpg" class="bg" true-img="img/3.jpg" alt=""> <img src="img/default.jpg" class="bg" true-img="img/4.jpg" alt=""> <img src="img/default.jpg" class="bg" true-img="img/5.jpg" alt=""> </div> </body>
</html> <script src="utils.js"></script> <script> let imgs = document.getElementsByClassName("bg"); function delay() { for (var i = 0; i < imgs.length; i++) { delayImg(imgs[i]); } }
function delayImg(img) { let imgH = img.offsetHeight; let winH = utils.win("clientHeight"); let imgT = utils.offset(img).top; let winT = utils.win("scrollTop"); if (winT + winH > imgH + imgT) { let trueSrc = img.getAttribute("true-img"); let newImg = new Image(); newImg.src = trueSrc; newImg.onload = function () { img.src = trueSrc; img.className = ""; newImg = null; }; } } delay(); window.onscroll = delay; </script> <script src="pratice2.js"></script>
|
utils
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
| let utils = (function () { function offset(el) { let left = el.offsetLeft; let top = el.offsetTop; let parent = el.offsetParent; while (parent !== document.body) { left += parent.offsetLeft + parent.clientLeft; top += parent.offsetTop + parent.clientTop; parent = parent.offsetParent; } return { left, top, }; }
function win(attr, val) { if (val == undefined) { return document.documentElement[attr] || document.body[attr]; } document.documentElement[attr] = val; document.body[attr] = val; } return { offset, win, }; })();
|