图片懒加载的关键在于获取元素的位置,并判断其是否出现在视口。
方法一:原生js实现
监听页面滚动,通过判断图片的offsetTop和可视区域高度+窗口滚去的距离,动态给图片的src添加图片路径(实测ok)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<style>
div {
padding-top: 800px;
background-color: red;
}
img {
width: 100px;
height: 100px;
display: block;
margin-bottom: 500px;
}
</style>
<body>
<div>
<img src="" data-src="./images/goodStudy.webp" alt="" />
<img src="" data-src="./images/fat.webp" alt="" />
<img src="" data-src="./images/awkward.webp" alt="" />
</div>
<script>
const img = document.querySelectorAll('img')
const clietH =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight //可视区域高度
window.onscroll = () => {
const scrollTop =
document.documentElement.scrollTop ||
window.pageYOffset ||
document.body.scrollTop //卷去的高度
img.forEach((item) => {
console.log(item)
if (item.offsetTop <= clietH + scrollTop) {
item.src = item.dataset.src
console.log(item.src)
}
})
}
</script>
</body>
</html>
方法二:使用Element.getBoundingClientRect() 方法
滚动监听+getBoundingClientRect()
Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。API返回一个对象,即rectObject为一个对象,其包含以下属性 rectObject.top:元素上边到视窗上边的距离; rectObject.right:元素右边到视窗左边的距离; rectObject.bottom:元素下边到视窗上边的距离; rectObject.left:元素左边到视窗左边的距离; rectObject.width:元素自身的宽度 rectObject.height:元素自身的高度
故当rectObject.top的值处于0-视口高度,则元素处于可视区。即 getBoundingClientRect(ele).top >= 0 && getBoundingClientRect(ele).top <= offsetHeight
方法三:使用vue-lazyload插件
使用:
-
npm install vue-lazyload --save 或者CDN: unpkg.com/vue-lazyloa…
-
引用文件,一般在main.js全局引用,且配置好图片
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
// or with options
Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png',
loading: 'dist/loading.gif',
attempt: 1
})
- vue文件中将需要懒加载的图片绑定 v-bind:src 修改为 v-lazy
<ul>
<li v-for="img in list">
<img v-lazy="img.src" >
</li>
</ul>
方法四:vueuse的use'Intersection'Obser方法——适用vue3
对于大量的图片,可以先封装一个自定义指令,再给图片绑定
// 图片懒加载
app.directive('lazy',{
mounted(el, binding){
const { stop } = useIntersectionObserver(el,([{ isIntersecting }]) => {
if(isIntersecting){
el.src = binding.value
stop()
// 如果图片加载失败了
el.onerror = () => {
el.src = defaultImg
}
}
})
}
})
使用:
方法五:使用内置api——》IntersectionObserver
<template>
<div>
<div class="box">1</div>
<div class="box target">2</div>
<div class="box target">3</div>
<div class="box target">4</div>
</div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
onMounted(() => {
const target = document.querySelectorAll('.target')
target.forEach((item) => {
const observe = new IntersectionObserver(function ([{ isIntersecting }]) {
console.log(666)
console.log(isIntersecting)
if (isIntersecting) {
observe.disconnect()
}
})
observe.observe(item)
})
})
</script>
<style lang="scss" scoped>
.box {
height: 1500px;
background-color: red;
}
.target {
background-color: skyblue;
}
</style>