vue3实现懒加载图片组件,外带loading

202 阅读2分钟

小白尝试实现了一款vue3的懒加载图片组件,借助自定义指令实现,有更好的建议欢迎提出

自定义懒加载图片组件,外带loading

导入loading动画

<template>
    <div class="loader">
        <div class="loader-square" style="--i:0s"></div>
        <div class="loader-square" style="--i:-1.4285714286s"></div>
        <div class="loader-square" style="--i:-2.8571428571s"></div>
        <div class="loader-square" style="--i:-4.2857142857s"></div>
        <div class="loader-square" style="--i:-5.7142857143s"></div>
        <div class="loader-square" style="--i:-7.1428571429s"></div>
        <div class="loader-square" style="--i:-8.5714285714s"></div>
    </div>
</template>

<style lang="scss" scoped>
.loader {
    position: relative;
    width: 96px;
    height: 96px;
    transform: rotate(45deg);

    &-square {
        position: absolute;
        top: 0;
        left: 0;
        width: 28px;
        height: 28px;
        margin: 2px;
        border-radius: 0px;
        background: white;
        background-size: cover;
        background-position: center;
        background-attachment: fixed;
        animation: square-animation 10s ease-in-out infinite both;
        animation-delay: var(--i);
    }
}
    @keyframes square-animation {
    0% {
        left: 0;
        top: 0;
    }

    10.5% {
        left: 0;
        top: 0;
    }

    12.5% {
        left: 32px;
        top: 0;
    }

    23% {
        left: 32px;
        top: 0;
    }

    25% {
        left: 64px;
        top: 0;
    }

    35.5% {
        left: 64px;
        top: 0;
    }

    37.5% {
        left: 64px;
        top: 32px;
    }

    48% {
        left: 64px;
        top: 32px;
    }

    50% {
        left: 32px;
        top: 32px;
    }

    60.5% {
        left: 32px;
        top: 32px;
    }

    62.5% {
        left: 32px;
        top: 64px;
    }

    73% {
        left: 32px;
        top: 64px;
    }

    75% {
        left: 0;
        top: 64px;
    }

    85.5% {
        left: 0;
        top: 64px;
    }

    87.5% {
        left: 0;
        top: 32px;
    }

    98% {
        left: 0;
        top: 32px;
    }

    100% {
        left: 0;
        top: 0;
    }
}
</style>

搭建自定义图片懒加载组件

基本结构

<template>
    <div class="img">
        <div class="img-loading">
            <Loading></Loading>
        </div>
        <img class="fade" />
    </div>
</template>
<script setup >
//导入loading组件
import Loading from './Loading.vue';
</script>
<style lang="scss" scoped >
.img{
    position: relative;
    width: 100%;
    &-loading{
        position: absolute;
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }
    img{
        width: 100%;
        height: 100%;
        object-fit: cover;
    }
    .fade{
        visibility: hidden;
    }
    .hide{
        display: none;
    }
}
</style>

设置.fade.hide目的是为了前期隐藏图片,后续展示图片和隐藏loading

编写自定义指令

function DefineLazy(app) {
  app.directive("lazy", {
    mounted(el, binding) {
      const observer = new IntersectionObserver(([{ intersectionRatio }]) => {
        if (intersectionRatio > 0) {
          const img = el.children[1];
          const loading = el.children[0];
          img.src = binding.value;
          img.onload = () => {
            img.classList.remove("fade");
            loading.classList.add("hide");
          };
          observer.unobserve(el);
        }
      });
      observer.observe(el);
    },
  });
}

export default DefineLazy;

这里借助IntersectionObserver中的intersectionRatio来判断是否已滚动页面到图片的相交处,从而添加链接展示图片,以此实现图片懒加载

其中,使用load事件将图片展示,loading去除

Vue中use自定义指令,实现注册

import { createApp } from 'vue'
import App from './App.vue'
import lazy from './hooks/lazy'
createApp(App)
.use(lazy)
.mount('#app')

正式使用

<Img v-lazy="val.src"/>

val.src为图片链接地址