【Vue3】25-自定义指令实现图片懒加载

310 阅读1分钟

1. 批量引入图片

// 批量引入图片
// { eager: true } 表示这是静态加载,类似于 import '...' from '...'
// 如果不写这个配置项,则表示这是动态加载,类似于 () => import('...')
let imgList: Record<string, { default: string }> = import.meta.glob('./assets/imgs/*.*', { eager: true })
console.log(imgList)  // 打印 1
console.log(imgList["./assets/imgs/img1.jpg"])  // 打印 2
let imgPathArr Object.values(imgList).map(v => v.default)
console.log(imgPathArr)  // 打印 3

打印 1 结果:以 [key: string]: object 形式组成的对象 [object Object]

image.png

打印 2 结果:

image.png

打印 3 结果:图片路径组成的一个数组

image.png

如果是动态加载

let imgList: Record<string, { default: string }> = import.meta.glob('./assets/imgs/*.*')
console.log(imgList)

打印结果:以 [key: string]: function 形式组成的对象 [object Object]

image.png

2. 实现图片懒加载

<template>
    <div>
        <img v-lazy="path" v-for="path in imgPathArr">
    </div>
</template>

<script setup lang="ts">
import { Directive, DirectiveBinding } from 'vue';

// 批量引入图片
let imgList: Record<string, { default: string }> = import.meta.glob('./assets/imgs/*.*', { eager: true })

let imgPathArr = Object.values(imgList).map(v => v.default)

const vLazy: Directive = async (el: HTMLImageElement, binding: DirectiveBinding) => {
    // 先加载一张默认图片,用来占位,提高用户体验
    const def = await import('./assets/vue.svg')
    el.src = def.default
    
    // 监视元素在可视区域内的占比
    const observer = new IntersectionObserver((enr) => {
        console.log(enr)  // 打印结果看下面的图片
        // 可以看到,enr[0].target 就是 observe() 传进来的那个元素,即要监视的元素
        console.log(enr[0].target  === el)  // true
        // intersectionRatio 表示元素有多少呈现在可视区域
        if(enr[0].intersectionRatio > 0){
            setTimeout(() => {  // 定时器模拟延迟
                // 给 img 元素绑定图片路径
                el.src = binding.value
                // 对已经加载完成的元素解除监视
                observer.unobserve(el)
            }, 200)
        }
    })
    // 指定要监视的元素
    observer.observe(el)
}

</script>

<style scoped>
div {
    height: 400px;
    width: fit-content;
    overflow: auto;
}
div img {
    display: block;
    width: 180px;
    height: 320px;
    border: 1px solid #ccc;
}</style>

image.png