Appearance
图片懒加载
lazy-load
是我们常见的优化方式,减少我们首屏图片请求个数,节省网络带宽。下面有几种实现方式 其实现原理如下图
基础实现
js
// 获取所有的图片标签
const imgs = document.getElementsByTagName("img");
// 获取可视区域的高度
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
// num用于统计当前显示到了哪一张图片,避免每次都从第一张图片开始检查是否露出
let num = 0;
function lazyload() {
for (let i = num; i < imgs.length; i++) {
// 用可视区域高度减去元素顶部距离可视区域顶部的高度
let distance = viewHeight - imgs[i].getBoundingClientRect().top;
// 如果可视区域高度大于等于元素顶部距离可视区域顶部的高度,说明元素露出
if (distance >= 0) {
// 给元素写入真实的src,展示图片
imgs[i].src = imgs[i].getAttribute("data-src");
// 前i张图片已经加载完毕,下次从第i+1张开始检查是否露出
num = i + 1;
}
}
}
// 监听Scroll事件
window.addEventListener("scroll", lazyload, false);
// 获取所有的图片标签
const imgs = document.getElementsByTagName("img");
// 获取可视区域的高度
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
// num用于统计当前显示到了哪一张图片,避免每次都从第一张图片开始检查是否露出
let num = 0;
function lazyload() {
for (let i = num; i < imgs.length; i++) {
// 用可视区域高度减去元素顶部距离可视区域顶部的高度
let distance = viewHeight - imgs[i].getBoundingClientRect().top;
// 如果可视区域高度大于等于元素顶部距离可视区域顶部的高度,说明元素露出
if (distance >= 0) {
// 给元素写入真实的src,展示图片
imgs[i].src = imgs[i].getAttribute("data-src");
// 前i张图片已经加载完毕,下次从第i+1张开始检查是否露出
num = i + 1;
}
}
}
// 监听Scroll事件
window.addEventListener("scroll", lazyload, false);
IntersectionObserver 实现
js
const imgs = document.querySelectorAll("img[data-src]");
const config = {
rootMargin: "0px",
threshold: 0,
};
let observer = new IntersectionObserver((entries, self) => {
entries.forEach((entry) => {
// 如果元素出现在视口内
if (entry.isIntersecting) {
let img = entry.target;
let src = img.dataset.src;
// 目标元素存在data-src
if (src) {
// 替换src
img.src = src;
img.removeAttribute("data-src");
}
// 解除观察
self.unobserve(entry.target);
}
});
}, config);
imgs.forEach((image) => {
observer.observe(image);
});
const imgs = document.querySelectorAll("img[data-src]");
const config = {
rootMargin: "0px",
threshold: 0,
};
let observer = new IntersectionObserver((entries, self) => {
entries.forEach((entry) => {
// 如果元素出现在视口内
if (entry.isIntersecting) {
let img = entry.target;
let src = img.dataset.src;
// 目标元素存在data-src
if (src) {
// 替换src
img.src = src;
img.removeAttribute("data-src");
}
// 解除观察
self.unobserve(entry.target);
}
});
}, config);
imgs.forEach((image) => {
observer.observe(image);
});
v-lazy 指令
js
export const lazyLoad = {
bind: function (el, binding) {
if (IntersectionObserver) {
// 目标图片
let targetSrc = binding.value; // 记录img原本要加载的图片地址
// 占位图
el.src = "xxx";
let lazyImageObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// 当前元素在视窗内可见
if (entry.intersectionRatio > 0) {
// 替换当前元素的src为目标图片地址
el.src = targetSrc;
// 使IntersectionObserver停止监听特定目标元素。释放资源
lazyImageObserver.unobserve(el);
}
});
});
// 使IntersectionObserver开始监听一个目标元素。
lazyImageObserver.observe(el);
}
},
};
export const lazyLoad = {
bind: function (el, binding) {
if (IntersectionObserver) {
// 目标图片
let targetSrc = binding.value; // 记录img原本要加载的图片地址
// 占位图
el.src = "xxx";
let lazyImageObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// 当前元素在视窗内可见
if (entry.intersectionRatio > 0) {
// 替换当前元素的src为目标图片地址
el.src = targetSrc;
// 使IntersectionObserver停止监听特定目标元素。释放资源
lazyImageObserver.unobserve(el);
}
});
});
// 使IntersectionObserver开始监听一个目标元素。
lazyImageObserver.observe(el);
}
},
};
html
<img v-lazy="目标图片" />
<img v-lazy="目标图片" />