Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
有时候我们的前端页面可能会包含很多图片,例如一些购物网站或者javascript高级程序设计图片网站。页面图片多,加载的图片就多,服务器压力就会很大。不仅影响页面渲染速度还会浪费带宽,比如一张1M大小的图片,同时有1000个人访问,就会产生1G的带宽。
为了解决这些问题,提高用户体验,就出现了懒加载的方式,那什么是懒加载呢,JavaScript就是进入页面的时候,只请求可javascript九九乘法表视区域的图片资源。懒嘛,我不会把全部图片都给你,你要看多少,我html就给你多少。
实现方式
html实现
这前端开发个是最简单的一种方式,直接给img标签加上loading=”lazy”
<img src="img/1.jpg" loading="lazy" />
js实现
我们通过js监听页浏览器历史记录设置面的滚动,判断当前图片是否到了可视区域:
- 拿到所有的图片dojavascript:void(0)m;
- 遍历每张图片判断当前图片是否到了可视区域范围内;
- 如果到了就设置图片的src属性;
- 绑定scroll事件,对其进行事件监听。
在页面初始化的时浏览器数据如何恢复候,图片的src放在dajavascript:void(0)ta-浏览器历史上的痕迹在哪里src属性上,当元素处于可视服务器地址范围内的时候,就把data-src赋值给src属性。
<body>
<img src="./img/default.png" data-src="./img/1.jpg" />
<img src="./img/default.png" data-src="./img/2.jpg" />
<img src="./img/default.png" data-src="./img/3.jpg" />
<img src="./img/default.png" data-src="./img/4.jpg" />
<img src="./img/default.png" data-src="./img/5.jpg" />
<img src="./img/default.png" data-src="./img/6.jpg" />
<img src="./img/default.png" data-src="./img/7.jpg" />
<img src="./img/default.png" data-src="./img/8.jpg" />
<img src="./img/default.png" data-src="./img/9.jpg" />
<img src="./img/default.png" data-src="./img/10.jpg" />
</body>
先获取所有图片dom,通过document.body.clientHeight获取可视区高度,再使用element.getBoundingClientRect()直接得到元素相对浏览的top值,遍历每张图html是什么意思片判断是否到了可视区浏览器历史记录设置内。
function lazyload() {
let viewHeight = document.body.clientHeight //获取可视区高度
let imgs = document.querySelectorAll('img[data-src]')
imgs.forEach((item, index) => {
if (item.dataset.src === '') return
// 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
let rect = item.getBoundingClientRect()
if (rect.bottom >= 0 && rect.top < viewHeight) {
item.src = item.dataset.src item.removeAttribute('data-src')
}
})
}
最浏览器的历史后绑定scroll事件
window.addEventListener('scroll', lazyload)
这样就完成了图片的懒加载操作了,不过呢,这样又重新带来了一个新的性能问题,因为页面滚动会不断地触发scroll事件,所以我们还需要一个“节流”函数。不知道节流函数的,可以看我前面的文章《JavaScri服务器内存条可以用在台式机上吗pt“防抖”和“节流”详解与应用》
// 节流函数
function throttle(fn, delay) {
let flag = true;
return function() {
if(!flag) return;
flag = false;
setTimeout(() => {
fn.apply(this, arguments);
flag = true;
}, delay)
}
}
然后给scroll加上节流
window.addEventListener('scroll', throttle(lazyload, 200))
大功告成!
如果是在vue中的话,我们可html网页制作以使用自定义指令v-lazy来完成图片懒加载
const LazyLoad = {
// install方法
install(Vue,options){
// 代替图片的loading图
let defaultSrc = options.default;
Vue.directive('lazy',{
bind(el,binding){
LazyLoad.init(el,binding.value,defaultSrc);
},
inserted(el){
// 兼容处理
if('IntersectionObserver' in window){
LazyLoad.observe(el);
}else{
LazyLoad.listenerScroll(el);
}
},
})
},
// 初始化
init(el,val,def){
// data-src 储存真实src
el.setAttribute('data-src',val);
// 设置src为loading图
el.setAttribute('src',def);
},
// 利用IntersectionObserver监听el
observe(el){
let io = new IntersectionObserver(entries => {
let realSrc = el.dataset.src;
if(entries[0].isIntersecting){
if(realSrc){
el.src = realSrc;
el.removeAttribute('data-src');
}
}
});
io.observe(el);
},
// 监听scroll事件
listenerScroll(el){
let handler = LazyLoad.throttle(LazyLoad.load,300);
LazyLoad.load(el);
window.addEventListener('scroll',() => {
handler(el);
});
},
// 加载真实图片
load(el){
let windowHeight = document.documentElement.clientHeight
let elTop = el.getBoundingClientRect().top;
let elBtm = el.getBoundingClientRect().bottom;
let realSrc = el.dataset.src;
if(elTop - windowHeight<0&&elBtm > 0){
if(realSrc){
el.src = realSrc;
el.removeAttribute('data-src');
}
}
},
// 节流
throttle(fn, delay) {
let flag = true;
return function() {
if(!flag) return;
flag = false;
setTimeout(() => {
fn.apply(this, arguments);
flag = true;
}, delay)
}
}
export default LazyLoad;