原理
在页面中有很多图片的时候,图片加载就需要很多时间,很耗费服务器性能,不仅影响渲染速度还会浪费带宽,为了解决这个问题,提高用户体验,所以就出现了懒加载这种方式来减轻服务器的压力,即优先加载可视区域的内容,其他部分等进入了可视区域再加载,从而提高性能。
思路
图片都是根据src进行加载的,在图片没有进入可视区域时,先不给src赋值(或者可以先给一个很小的loading图),等到图片进入可视区域再给src赋真正的值。图片的真实地址可以先存储在data-src中。
实现
<div>
<h6>图片懒加载</h6>
<img data-src="/static/images/login-bg-3.jpg" src="/static/images/login-bg-4.jpg"><br>
<img data-src="/static/images/login-bg-1.jpg" src="/static/images/login-bg-4.jpg"><br>
<img data-src="/static/images/login-bg.jpg" src="/static/images/login-bg-4.jpg"><br>
<img data-src="/static/images/login-bg-3.jpg" src="/static/images/login-bg-4.jpg"><br>
<img data-src="/static/images/login-bg-old.jpg" src="/static/images/login-bg-4.jpg"<br>
<img data-src="/static/images/login-bg-1.jpg" src="/static/images/login-bg-4.jpg"><br>
<img data-src="/static/images/login-bg.jpg" src="/static/images/login-bg-4.jpg"><br>
</div>
wx公众号【编程十点半】回复【前端】加入前端交流大家庭~~,
更多干获及面试真题——> B站【程序员Rita】~~
1. getBoundingClientRect API 实现
data(){
return{
flag: true
}
},
created() {
//this.lazyLoad();
this.throttle(this.lazyLoad, 3000)() //首次进入加载
},
mounted() {
const that = this;
window.addEventListener('scroll',()=>{
that.throttle(that.lazyLoad, 2000)()
//that.lazyLoad()
})
},
methods:{
//节流优化
throttle(fn, delay){
const that = this;
return function () {
if (!that.flag) return;
that.flag = false; //没执行过就一直是false,会直接return
setTimeout(() => {
fn.apply(that, arguments);
that.flag = true; //setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
}, delay);
}
},
lazyLoad(){
let images = document.getElementsByTagName('img') //不是数组,htmlCollection遍历时要注意
//加定时器的目的是为了让images能够遍历到
setTimeout(()=>{
for(let i =0;i<images.length;i++){
if(images[i].getBoundingClientRect().top<document.body.clientHeight){ //getBoundingClientRect().top 元素的上边相对浏览器视窗的位置如果小于可视窗口的高度
images[i].src = images[i].dataset.src;
}
}
},300)
}
}
2. 元素的offsetTop API 实现
写法与第一种基本相似,判断进入可视区域的条件有变,通过下图,可以看出,这里进入可视区域的判断条件是某一元素e的
e.offsetTop < document.body.clientHeight + document.body.scrollTop
3. IntersectionObserver API 实现
IntersectionObserver API
,可以自动"观察"元素是否可见,Chrome 51+
已经支持。由于可见(visible
)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做交叉观察器
。
created() {
this.intersectionObserver();
},
methods:{
intersectionObserver(){
let images = document.getElementsByTagName('img');
const observer = new IntersectionObserver((imgs) => {
console.log('imgs===', imgs)
// imgs: 目标元素集合
imgs.forEach((img) => {
// img.isIntersecting代表目标元素可见,可见的时候给src赋值
if (img.isIntersecting) {
const item = img.target
item.src = item.dataset.src
observer.unobserve(item);
}
})
})
//定时器和Array.from的目的是让images可遍历
setTimeout(()=>{
Array.from(images).forEach(item => {
observer.observe(item);
})
},300)
}
}
imgs的打印如下:
isIntersecting 代表该目标元素可见,可以加载;target 即对应页面中的真实img。
4. vue-lazyload 插件实现
(1)安装插件
npm install vue-lazyload --save-dev
(2)在main.js文件中引入并使用
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
(3)修改图片显示方式为懒加载(将 :src="xxx" 属性直接改为v-lazy="xxx")