图片懒加载的原理
1.给图片设置个data- 的自定义属性
2.初始,图片为自定义属性无值
3.当图片可见值data- 属性变为src有值,去加载图片
如何判断元素是否可见?
之前: scrollTop,offsetT,height...计算...
现在: 浏览器有一个API,intersectionObserver 可以监听元素是否可见
开发中,有vueuse中的useIntersectionObserver 这个api
useIntersectionObserver 的基本使用
在 src - views - .vue
<script setup lang="ts">
import { useIntersectionObserver } from '@vueuse/core'
import { onMounted, ref } from 'vue';
const imgRef = ref(null)
// 实时这个dom是否在可视区内
// const { stop } = useIntersectionObserver(要监视的dom, ([{ isIntersecting }]) => {
// // 回调函数: 当 isIntersecting 变化时:从可见->不可见; 不可见->可见
// isIntersecting: 当前是否可见?
// })
// stop: 停止监听
onMounted(() => {
const { stop } = useIntersectionObserver(imgRef.value, ([ { isIntersecting }]) => {
console.log('是否进入?', isIntersecting )
} )
setTimeout(() => {
console.log('停止监视...')
stop()
}, 5000)
})
</script>
<template>
<img ref="imgRef" width="200" height="200" />
</template>
封装自定义指令
src/directive/directive.ts
import { useIntersectionObserver } from "@vueuse/core";
import { App } from "vue";
//自定义指令
export default {
install(app:App) {
//全局指令
app.directive('lazy',{
//mounted是
mounted (el,binding) {
console.log('lazy',el,binding.value);
const {stop} = useIntersectionObserver(el,([{isIntersecting}]) =>{
if (isIntersecting) {
el.src = binding.value
//停止
stop()
}
})
}
})
}
}
src/main.ts
import XtDirective from '@/directive/directive'
app.use(XtDirective)
懒加载图片基本实现
在 src - views - Layout/Layout.vue
<script setup lang="ts">
import { useIntersectionObserver } from '@vueuse/core'
import { onMounted, ref } from 'vue';
const imgRef = ref<null | HTMLImageElement>(null)
// 实时这个dom是否在可视区内
// const { stop } = useIntersectionObserver(要监视的dom, ([{ isIntersecting }]) => {
// // 回调函数: 当 isIntersecting 变化时:从可见->不可见; 不可见->可见
// isIntersecting: 当前是否可见?
// })
// stop: 停止监听
onMounted(() => {
const { stop } = useIntersectionObserver(imgRef.value, ([ { isIntersecting }]) => {
//console.log('是否进入?', isIntersecting )
console.log('是否进入?', isIntersecting, imgRef.value?.dataset.src )
} )
// 如果图片可见,则设置它的src为 data-src的值
if(isIntersecting){
if(imgRef.value){
imgRef.value.src = imgRef.value.dataset.src || ''
}
// 停止观察监听
stop()
}
} )
})
</script>
<template>
<img
ref="imgRef"
data-src="https://yanxuan-item.nosdn.127.net/79f289a4e975fd030d5c37b98b9282c5.jpg"
width="200" height="200" />
</template>
而后在其他文件中 将 :src 改为 v-lazy即可
但是呢,也会出现图片加载失败的情况 - 因此要给图片设置默认图片
在 src/directive/directive.ts中修改
import { useIntersectionObserver } from "@vueuse/core";
import { App } from "vue";
import defaultImg from '../assets/images/loading.gif'
//自定义指令
export default {
install(app:App) {
//全局指令
app.directive('lazy',{
//el是dom元素
mounted (el,binding) {
//设置默认图
el.src = defaultImg
//console.log('lazy',el,binding.value);
//实时监听el是否可见,如果可见,给它的src设置 binding.value
const {stop} = useIntersectionObserver(el,([{isIntersecting}]) =>{
if (isIntersecting) {
el.src = binding.value
//停止
stop()
}
})
}
})
}
}