文章首次发表在 我的博客
当咱们向下滚动的时候图片资源才被请求到,这也就是咱们本次要实现的效果,进入页面的时候,只请求可视区域的图片资源这也就是懒加载。html
好比咱们加载一个页面,这个页面很长很长,长到咱们的浏览器可视区域装不下,那么懒加载就是优先加载可视区域的内容,其余部分等进入了可视区域在加载。vue
这个功能很是常见,你打开淘宝的首页,向下滚动,就会看到会有图片不断的加载;你在百度中搜索图片,结果确定成千上万条,不可能全部的都一会儿加载出来的,很重要的缘由就是会有性能问题。你能够在Network中查看,在页面滚动的时候,会看到图片一张张加载出来。node
懒加载是一种网页性能优化的方式,它能极大的提高用户体验。就好比说图片,图片一直是影响网页性能的主要元凶,如今一张图片超过几兆已是很常常的事了。若是每次进入页面就请求全部的图片资源,那么可能等图片加载出来用户也早就走了。因此,咱们须要懒加载,进入页面的时候,只请求可视区域的图片资源。git
总结出来就两个点:github
1.所有加载的话会影响用户体验express
2.浪费用户的流量,有些用户并不像所有看完,所有加载会耗费大量流量。npm
图片的标签是 img
标签,图片的来源主要是 src属性,浏览器是否发起加载图片的请求是根据是否有src属性决定的。api
因此能够从 img
标签的 src属性入手,在没进到可视区域的时候,就先不给 img 标签的 src属性赋值。浏览器
实现效果图:性能优化
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div { display: flex; flex-direction: column; } img { width: 100%; height: 300px; } </style> </head> <body> <div> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657907683.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657913523.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657925550.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657930289.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657934750.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657918315.jpeg"> </div> </body> </html>
const imgs = [...document.getElementsByTagName('img')]; let n = 0; lazyload(); function throttle(fn, wait) { let timer = null; return function(...args) { if(!timer) { timer = setTimeout(() => { timer = null; fn.apply(this, args) }, wait) } } } function lazyload() { var innerHeight = window.innerHeight; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; for(let i = n; i < imgs.length; i++) { if(imgs[i].offsetTop < innerHeight + scrollTop) { imgs[i].src = imgs[i].getAttribute("data-src"); n = i + 1; } } } window.addEventListener('scroll', throttle(lazyload, 200));
可能会存在下面几个问题:
getboundingclientrect
获取Intersection Observer API提供了一种异步观察目标元素与祖先元素或顶级文档viewport的交集中的变化的方法。
建立一个 IntersectionObserver对象,并传入相应参数和回调用函数,该回调函数将会在目标(target)元素和根(root)元素的交集大小超过阈值(threshold)规定的大小时候被执行。
var observer = new IntersectionObserver(callback, options);
IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数(即目标元素出如今root选项指定的元素中可见时,回调函数将会被执行),option是配置对象(该参数可选)。
返回的 observer
是一个观察器实例。实例的 observe 方法能够指定观察哪一个DOM节点。
具体的用法能够 查看 MDN文档
const imgs = [...document.getElementsByTagName('img')]; // 当监听的元素进入可视范围内的会触发回调 if(IntersectionObserver) { // 建立一个 intersection observer let lazyImageObserver = new IntersectionObserver((entries, observer) => { entries.forEach((entry, index) => { let lazyImage = entry.target; // 相交率,默认是相对于浏览器视窗 if(entry.intersectionRatio > 0) { lazyImage.src = lazyImage.getAttribute('data-src'); // 当前图片加载完以后须要去掉监听 lazyImageObserver.unobserve(lazyImage); } }) }) for(let i = 0; i < imgs.length; i++) { lazyImageObserver.observe(imgs[i]); } }
下面的api来自官网自定义指令:
指令钩子函数会被传入如下参数:
binding:一个对象,包含如下 property:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> img { width: 100%; height: 300px; } </style> </head> <body> <div id="app"> <p v-for="item in imgs" :key="item"> <img v-lazyload="item"> </p> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> Vue.directive("lazyload", { // 指令的定义 bind: function(el, binding) { let lazyImageObserver = new IntersectionObserver((entries, observer) => { entries.forEach((entry, index) => { let lazyImage = entry.target; // 相交率,默认是相对于浏览器视窗 if(entry.intersectionRatio > 0) { lazyImage.src = binding.value; // 当前图片加载完以后须要去掉监听 lazyImageObserver.unobserve(lazyImage); } }) }) lazyImageObserver.observe(el); }, }); var app = new Vue({ el: "#app", data: { imgs: [ 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657907683.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657913523.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657925550.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657930289.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657934750.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657918315.jpeg', ] }, }); </script> </html>