vue3实现vue2的v-lazy懒加载指令

395 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 13 天、第 13 篇,点击查看活动详情

前言

开发自己项目时想用上图片懒加载,但是百度了一下vue2的v-lazy在vue3已经被弃用了,因此便搜索vue3有没有类似的api但是并没有发现,因此从网上了解到了IntersectionObserver这样一个浏览器api,并用他实现了图片懒加载

图片懒加载的原理已经是老生常谈了,等到图片组件出现在视口内再加载图片,是一种很常见的优化手段,对于图片是否出现在视口的监听,我们仍然可以使用监听scroll或者使用setInterval来判断实现,但是监听scroll会有触发过于频繁而产生性能问题,监听setInterval因为是给其设定一个间歇执行的函数,与理想效果也会有出入,而IntersectionObserver提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法(这是官方的说法),也就是可以实现监听元素在其祖先元素(默认顶级文档视窗)的可视状态

我们利用Vue3的自定义指令,我这里自定义了一个v-lazyload指令,在需要懒加载的img标签上使用,在页面刚渲染时为它绑定IntersectionObserver监听器,直到目标元素是否出现在了视口才将图片链接绑定在标签的src属性上,如果图片加载失败显示默认图片。

实现

IntersectionObservera接受两个参数

第一个参数是一个函数,也就是监听的回调,传入的参数是一个对象数组,包含祖先元素与目标元素的信息以及一些参数,第二个参数是配置属性,可选,详情可参考IntersectionObserver

以下为实现代码

import defaultImg from '@/assets/img/products/product_placeholder_square_medium.jpg'
//图片加载失败是现实的图片
const defineDirective = (app) => {
    // 扩展自定义指令
    app.directive('lazyload', {
        // Vue3种自定义指令关联到了生命周期,这里使用mounted
        mounted(el, bindings) {
            // el表示使用指令的DOM元素
            // bindings表示指令传入的内容,是一个对象
            
            // 1、用IntersectionObserver监听图片进入可视区
            const oberver = new IntersectionObserver((cahnges) => {
                // console.log(cahnges)
                if (cahnges[0].isIntersecting) {
                    // console.log(isIntersecting, bindings.value)
                    // 进入了可视区
                    // 2、给图片的src属性赋值图片的地址
                    el.src = bindings.value
                        // 取消图片的监听
                    oberver.unobserve(el)
                        // 加载的图片失败了,显示默认的图片地址
                    el.onerror = () => {
                        // 显示默认图片
                        el.src = defaultImg
                    }
                }
            })//不配置第二个参数,使用API的默认配置
            oberver.observe(el)//挂载监听器
        }
    })
}

export default {
    install(app) {// 自定义指令指令导出
        defineDirective(app)
    }
}

将这部分代码封装成自己的api以后,在全局注册

import { createApp } from 'vue'

import App from './App.vue'

import imgLazy from '@/utils/imgLazy.js'
const app = createApp(App)

app.use(imgLazy)

app.mount('#app')

之后在组件中使用就跟vue2中没差别,直接在需要懒加载的标签使用v-lazyload指令就可以。

<figure class="imgBox">
    <img v-lazyload="props.imgA" class="imgA" />
    <img v-if="props.imgB" v-lazyload="props.imgB" class="imgB"/>
</figure>

记得v-lazyload要绑定自己的图片的链接,是不是非常的简单又实用

最后再打个广告,关注公众号程序猿青空,不定期分享各种优秀文章、学习资源、学习课程,能在未来(因为现在还没啥东西)享受更多福利。