(一)懒加载
1. 什么是懒加载
懒加载,即延迟加载。在访问页面时,先将 img
元素或其他元素的背景图片路径替换为占位图(通常是 1*1px 的小图片),仅当元素进入浏览器可视区域时,才设置其真实的图片路径并显示图片。这有效避免了页面初次加载时一次性请求大量图片资源。
2. 为何使用懒加载
如今很多页面内容丰富、篇幅长且图片众多,如各类商城页面。这些图片体积较大,少则百来 K,多则上兆。若页面载入时一次性加载全部图片,会极大延长页面加载时间,降低用户体验。
3. 懒加载的优点
-
提升页面加载速度:减少了初始加载时的请求资源数量,让页面更快呈现给用户。
-
减轻服务器压力:降低了同一时间内服务器需要处理的请求量。
-
节约流量:用户仅在需要查看图片时才加载,避免不必要的流量消耗。
-
优化用户体验:快速加载的页面能让用户更流畅地浏览内容。
4. 懒加载的原理
页面中的 img
元素若没有 src
属性,浏览器不会发起图片下载请求。懒加载利用这一特性,先使用占位图填充 img
元素,将真实图片路径存储在自定义属性(如 data-original
)中,当元素进入可视区域时,再将自定义属性的值赋给 src
属性,触发图片加载。
5. 懒加载的实现步骤
-
存储真实路径:将图片的真实路径存放在自定义属性(如
data-original
或data-src
)中,而非src
属性。 -
判断可视区域:页面加载完成后,实时判断图片是否进入用户的可视区域,若是,则将自定义属性中的真实路径赋值给
src
属性。
6. 懒加载实现方式
html结构
1、 obj.getAttribute("属性名")通过元素节点的属性名称获取属性的值。
2、使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放, dataset 获取自定义属性值的使用
<ul><li><img data-src="./img/img1.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img2.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img3.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img4.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img5.png" src="./img/loading.gif" alt="" /></li></ul>
(第一种)基于元素高度计算
元素距顶部的高度 - 页面被卷去的高度 <= 浏览器可视区的高度)
来判断是否符合我们想要的条件.需要实时监听页面滚动时 图片的高度变化
<ul><li><img data-src="./img/img1.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img2.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img3.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img4.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img5.png" src="./img/loading.gif" alt="" /></li></ul>
<script>window.onload = function () {const imgs = document.querySelectorAll("img");// 初始化执行lazyLoad(imgs);// 滚动执行window.addEventListener("scroll", function () {lazyLoad(imgs);});function lazyLoad(imgs) {for (let i = 0; i < imgs.length; i++) {const imgoffsetT = imgs[i].offsetTop; // 图片距顶部的高度const wheight = window.innerHeight; // 浏览器可视区的高度const scrollT = document.documentElement.scrollTop || document.body.scrollTop; // 页面被卷去的高度if (imgoffsetT - scrollT <= wheight) {// 判断图片是否将要出现imgs[i].src = imgs[i].dataset.src; // 出现后将自定义地址转为真实地址}}}};
</script>
这种方式通过计算元素距顶部的高度、页面被卷去的高度和浏览器可视区的高度,判断图片是否进入可视区域。需要注意的是,不同浏览器对 document.documentElement.scrollTop
和 document.body.scrollTop
的支持有所差异,因此要同时考虑这两个属性。
(第二种)使用 getBoundingClientRect()
方法
getBoundingClientRect()
——获取元素位置,这个方法没有参数
——用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。
——是DOM元素到浏览器可视范围的距离(不包含文档卷起的部分)。
该函数返回一个Object对象,该对象有6个属性:top,lef,right,bottom,width,height;
<ul><li><img data-src="./img/img1.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img2.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img3.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img4.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img5.png" src="./img/loading.gif" alt="" /></li></ul>
<script>window.onload = function () {const imgs = document.querySelectorAll("img");// 初始调动一次lazyLoad();// 监听滚动时,再调用函数window.addEventListener("scroll", throttle(lazyLoad, 1000), false);// 函数 1: 封装判定图片是否在可视区function isInVisibleArea(imgOne) {const info = imgOne.getBoundingClientRect();// 获取页面可视区的高度,宽度const windowH = window.innerHeight;const windowW = window.innerWidth;// 限定参数在可视区内const res = info.bottom > 0 && info.top < windowH && info.right > 0 && info.left < windowW;return res;}// 函数 2: 封装滚动时重新加载函数function lazyLoad() {for (let i = 0; i < imgs.length; i++) {const imgOne = imgs[i];// 判定是否在可视区内if (isInVisibleArea(imgOne)) {// 替换 src 方法一:// imgOne.src = imgOne.getAttribute("data-src");// 替换 src 方法二:imgOne.src = imgOne.dataset.src;}}}// 函数 3: 节流函数function throttle(fn, time = 250) {let lastTime = null;return function (...args) {const now = Date.now(); // 当前时间if (!lastTime || now - lastTime >= time) {fn.apply(this, args); // 帮助执行函数,改变上下文lastTime = now;}};}};
</script>
getBoundingClientRect()
方法可获取元素相对浏览器视窗的位置信息。为避免滚动事件频繁触发导致性能问题,使用了节流函数 throttle
来限制函数的调用频率。
(第三种)使用 IntersectionObserver
IntersectionObserver(callback)
callback函数会触发两次,元素进入视窗(开始可见时)和元素离开视窗(开始不可见时)都会触发
<ul><li><img data-src="./img/img1.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img2.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img3.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img4.gif" src="./img/loading.gif" alt="" /></li><li><img data-src="./img/img5.png" src="./img/loading.gif" alt="" /></li></ul>
<script>const imgs = document.querySelectorAll("img");const callback = function (res) {// res 是观察的元素数组,info 每个被观察的图片信息res.forEach(function (info) {// isIntersecting 目标是否被观察到,返回布尔值if (info.isIntersecting) {// img 就是当前的图片标签const img = info.target;img.src = img.getAttribute("data-src");// 真实地址替换后取消对它的观察obs.unobserve(img);}});};// 实例化 IntersectionObserverconst obs = new IntersectionObserver(callback);// 遍历 imgs 所有的图片,然后给每个图片添加观察实例imgs.forEach(function (img) {// observe: 被调用的 IntersectionObserver 实例。给每个图片添加观察实例obs.observe(img);});
</script>
IntersectionObserver
是一种更高效的懒加载实现方式,它会在元素进入或离开视窗时触发回调函数。当元素进入视窗时,将真实图片路径赋值给 src
属性,并取消对该元素的观察,避免重复操作。
(二)预加载
1. 什么是预加载
资源预加载是一种性能优化技术,它提前告知浏览器某些资源在未来可能会被使用,并将这些资源提前请求加载到本地。当需要使用这些资源时,可直接从本地缓存中获取,从而提高页面响应速度。
2. 为何使用预加载
对于内容庞大的页面,如果不使用预加载技术,用户可能会长时间看到空白页面,直到所有内容加载完成。预加载可以在页面全部加载之前,提前加载主要内容,减少用户等待时间,提升用户体验。
3. 预加载实现方式
<!-- 需求:实现点击图片,切换下一张图片 -->
<div><p></p><img src="./img/img1.gif" alt="" />
</div>
<script>const imgs = ["./img/img2.gif", "./img/img3.gif", "./img/img4.gif", "./img/img5.png"];const img = document.querySelector("img");const test = document.querySelector("p");// 实现点击切换下一张图片let index = 0;test.innerHTML = "我是第" + (index + 1) + "张图片";img.addEventListener("click", function () {if (index < imgs.length) {img.src = imgs[index];index++;test.innerHTML = "我是第" + (index + 1) + "张图片";} else {alert('没有了');}// 切换图片后,同时让浏览器提前加载下载一张图片if (index < imgs.length) {preLoad(imgs[index]);}});// 调用加载函数,页面一开始就加载数组第一个元素preLoad(imgs[0]);// 封装函数,新建一个 img 标签,然后增加 src 属性,让浏览器加载下一张图片function preLoad(src) {const newImg = new Image();newImg.src = src;}
</script>
上述代码通过点击图片切换显示内容,并在切换后预加载下一张图片。通过创建一个新的 Image
对象并设置其 src
属性,触发浏览器对图片的预加载。