1.图片懒加载有两种方式
默认图片可视区由父元素的高度决定
1.1 第一种使用offsetTop
步骤一: 获取图片元素列表
//父元素
let box = document.querySelector(".box");
//元素列表
let elements = document.querySelectorAll("img");
步骤二:遍历元素列表
elements.forEach((item, index) => {
})
步骤三:判断图片是否在可视区
//得到每个元素相对于父元素可视区top距离
let positionY = item.offsetTop - '第一个img相对有offsetParent属性的父元素的距离';
//这里注意:如果box父元素有设置paddingtop,这里减去的就是box父元素相对含有offsetParent属性的父元素的距离
// img元素相对含offsetParent属性的父元素的距离-滚动条滚动的距离<可视区的高度 就说明图片已经进入可视区
if (positionY-box.scrollTop < box.clientHeight) {
let url = arr[index].imgUrl;
arr[index].imgUrl=""
arr[index].real_url = url
}
注意:offsetTop不是相对父元素的距离,而是相对含offsetParent属性的上层元素的距离,而 含有 定位属性(position)的元素或者 本身就是 table,td,th,body 的元素,就具备 offsetParent的属性,如果没有就是相对于body。
图示:当我去掉box的父元素的position定位之后首元素的offsetTop从60变为688,也就是变成相对于body的距离了。
图示:图片高度为100px,间距为10px
示例代码:
<template>
<div class="box">
<div
class="box-item"
v-for="(item, index) in datalist"
:key="index"
>
<img :src="item.real_url" lazyload="true" :data-original="item.imgUrl" />
</div>
</div>
</template>
<script>
import { onMounted,onBeforeMount, ref } from "vue";
export default {
setup() {
const datalist = ref([
{
imgUrl: require("@/assets/bookface/cloud.png"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/河.jpg"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/snow.jpg"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/smoke.jpg"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/chonga.jpg"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/addoil.jpg"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/cloud.png"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/河.jpg"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/black.jpeg"),
real_url: "",
},
{
imgUrl: require("@/assets/bookface/moon.jpeg"),
real_url: "",
},
]);
onBeforeMount(()=>{
document.addEventListener("scroll",LazyLoad,true)
})
onMounted(() => {
LazyLoad();
});
const LazyLoad = () => {
const arr = datalist.value;
let box = document.querySelector(".box");
let elements = document.querySelectorAll("img");
elements.forEach((item, index) => {
let positionY = item.offsetTop - '第一个img相对有offsetParent属性的父元素的距离';
if(!arr[index].imgUrl){
return
}
if (positionY-box.scrollTop < box.clientHeight) {
let url = arr[index].imgUrl;
arr[index].imgUrl=""
arr[index].real_url = url
}
});
};
return {
datalist,
LazyLoad,
};
},
};
</script>
<style lang="less" scoped>
.box {
width:280px;
height: 400px;
overflow: hidden;
overflow-y: scroll;
display: flex;
flex-wrap: wrap;
align-items: center;
&-item {
box-sizing: border-box;
width: 120px;
height: 100px;
background: cornflowerblue;
margin-right: 10px;
margin-bottom: 10px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.box-item:nth-of-type(even) {
margin-right: 0;
}
.border {
border: 2px solid salmon;
}
}
</style>
1.2 第二种使用getBoundingClientRect
先了解一个api,getBoundingClientRect()可以获取元素的大小及位置,返回的是一个DOMRect的对象,包含元素的宽高,以及相对屏幕视口的位置。当图片滚动,图片位置发生变化,会触发getBoundingClientRect()返回每个元素相对视口的位置,所以我们可以根据 当元素相对视口的top值<=可视区的时候,就说明图片已经进入可视区(默认图片可视区为整个视口高度,如果不是的话需要减去可视区相对视口的top值)。
核心代码:
const LazyLoad = () => {
let box = document.querySelector(".box"); //父元素
let elements = document.querySelectorAll("img"); //图片子元素集合
elements.forEach((item, index) => {
let positionY = item.getBoundingClientRect().top - '可视区相对屏幕视口的高度';
if(!arr[index].imgUrl){
return
}
if (positionY<=box.clientHeight) {
//把图片地址赋给真实地址
}
});
};