什么是图片懒加载?
默认情况下不加载图片,直到滚动页面,图片进入浏览器窗口的可视区域,才加载图片!
图片懒加载效果预览
图片懒加载实现原理
图片默认的src属性为空,图片地址存放在data-src属性中,当图片进入可视区域,从data-src属性中取得图片地址,赋值给src属性完成图片的加载
图片懒加载的实现方案
- 全局监听浏览器滚动事件
- 滚动事件中判断是否有图片进入可视区域
- 若图片进入可视区域,则加载图片
- 加载图片的过程为:从data-src属性中取得图片地址,赋值给src属性
图片懒加载的完整范例代码
目录结构
index.html
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <div style="height: 1000px"> <img src="./images/1.jpg" /> </div> <div> <img class="lazy-element" data-src="./images/2.jpg" /> </div> <div> <img class="lazy-element" data-src="./images/3.jpg" /> </div> <div> <img class="lazy-element" data-src="./images/4.jpg" /> </div> <script type="text/javascript" src="./lazy.js"></script> </body> </html>
lazy.js
/* 图片懒加载的原理: 图片默认的src属性为空,图片地址存放在data-src属性中 >> 当图片进入可视区域 - 从data-src属性中取得图片地址,赋值给src属性完成图片的加载 图片懒加载的实现方案: 1. 全局监听浏览器滚动事件 2. 滚动事件中判断是否有图片进入可视区域 3. 若图片进入可视区域,则加载图片 4. 加载图片的过程为:从data-src属性中取得图片地址,赋值给src属性 */ // 设定懒加载元素的样式名为 lazy-element let lazyElementClassName = "lazy-element"; // 设定存储图片地址的属性为 data-src let srcAttrName = "data-src"; // 定义变量--存储浏览器窗口的高度; let _viewportHeight; // 定义变量--存储浏览器窗口与页面顶部的距离; let _pageYOffset; // 更新浏览器窗口的高度 function setViewportHeight() { _viewportHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; } // 更新浏览器窗口与页面顶部的距离 function setPageYOffset() { _pageYOffset = window.pageYOffset || window.scrollY || document.documentElement.scrollTop || document.body.scrollTop; } // 通过 getElementsByClassName 获取所有懒加载元素(数据类型为类似数组的HTMLCollection) // 使用Array.prototype.slice.call方法将HTMLCollection转化为数组 let elements = Array.prototype.slice.call( document.getElementsByClassName(lazyElementClassName) ); // 设定一个标记 —— 页面是否滚动(默认未滚动) let initialized = false; // 初始化浏览器窗口的高度 setViewportHeight(); // 全局监听浏览器滚动事件 window.onscroll = function () { // 浏览器滚动时,触发懒加载图片的检测 scrollEventHandler(); // 页面滚动时,更新浏览器窗口与页面顶部的距离 setPageYOffset(); }; // 全局监听浏览器窗口大小改变事件 window.onresize = function () { // 浏览器窗口大小改变时,更新浏览器窗口的高度 setViewportHeight(); }; function scrollEventHandler() { // 页面滚动时 if (!initialized) { requestAnimationFrame(function update() { // 判断是否加载图片 checkAvailable(); // requestAnimationFrame 的回调函数只会被调用一次,如果希望每帧都执行,则每帧都需要调用 requestAnimationFrame(update); }); } // 滚动过后,标记为页面已滚动 initialized = true; } // 判断是否加载图片 function checkAvailable() { for (let i = 0; i < elements.length; i++) { let el = elements[i]; // 一旦检测发现进入可视区域 if (checkElementIsInViewport(el)) { // 则加载图片 loadElement(el); // 并将该元素踢出队列 elements.splice(i--, 1); } } } // 判断元素是否进入可视区域 function checkElementIsInViewport(elem) { if (elem.getBoundingClientRect) { // getBoundingClientRect方法用于获取元素相对于视口左上方的位移; let elemPos = elem.getBoundingClientRect(); // 元素与视口顶部的距离小于或等于视口高度时,元素进入可视区域 if (elemPos.top && elemPos.top > 0 && elemPos.top <= _viewportHeight) { return true; } return false; } else { // 兼容不支持getBoundingClientRect的浏览器 let offsetTop = getElemOffsetTop(elem); // 元素与页面顶部的距离小于或等于视口高度+视口顶部与页面顶部的距离时,元素进入可视区域 if ( offsetTop > _pageYOffset && offsetTop < _pageYOffset + _viewportHeight ) { return true; } return false; } } // 获取元素与页面顶部的距离 function getElemOffsetTop(el) { let top = el.offsetTop; let parent = el.offsetParent; while (parent) { top += parent.offsetTop || 0; parent = parent.offsetParent; } return top; } // 加载图片: 从data-src属性中取得图片地址,赋值给src属性 function loadElement(elem) { let srcURL = elem.getAttribute(srcAttrName); elem.src = srcURL; }