实现图片懒加载的五种方法

351 阅读1分钟

图片懒加载的关键在于获取元素的位置,并判断其是否出现在视口。

方法一:原生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插件

使用:

  1. npm install vue-lazyload --save 或者CDN: unpkg.com/vue-lazyloa…

  2. 引用文件,一般在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
})
  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>