拿来吧!图片懒加载

155 阅读1分钟

2022-05-07 15-16-05_.gif 原理: img标签统一自定义属性data-src='default.png',当检测到图片出现在窗口之后再补充src属性,此时才会进行图片资源加载

原生写法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-wrap: wrap;
      }
      img {
        width: 400px;
        height: 400px;
      }
    </style>
  </head>
  <body>
    <!-- 可以给img标签统一自定义属性data-src='default.png',当检测到图片出现在窗口之后再补充src属性,此时才会进行图片资源加载。 -->
    <div class="box">
      <img data-src="http://pic.616pic.com/ys_img/00/79/81/FTVKUmzD8E.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/07/10/dKr1dCXshx.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/08/05/88rYhZkGBm.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/11/26/tQ9RAXG5SE.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/12/26/WPsNV0b8Po.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/28/74/vXD17fgSzV.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/03/99/c5bqRIQ2mY.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/03/62/z8rGeMvQwJ.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/14/83/vdzed0sUfo.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/75/27/mwlBaFXGSV.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/76/75/dfjKrC9Sx5.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/84/96/xBW5RPyOoq1.jpg">
      <img data-src="http://pic.616pic.com/ys_img/00/85/08/thbRwvoP9z.jpg">
    </div>
    <script>
      function lazyload() {
        const imgs = document.getElementsByTagName('img')
        const len = imgs.length
        // 视口的高度
        const viewHeight = document.documentElement.clientHeight
        // 滚动条高度
        const scrollHeight = document.documentElement.scrollTop || document.body.scrollTop
        for (let i = 0; i < len; i++) {
          const offsetHeight = imgs[i].offsetTop
          if (offsetHeight < viewHeight + scrollHeight) {
            const src = imgs[i].dataset.src
            imgs[i].src = src
          }
        }
      }
      lazyload()
      // 可以使用节流优化一下
      window.addEventListener('scroll', lazyload)
    </script>
  </body>
</html>

vue中的使用

  1. main.js中全局动态注册自定义指令
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
+ import * as directives from '@/directives'
const app = createApp(App)
+ Object.keys(directives).forEach(key => {
+   app.directive(key, directives[key])
+ })
app.use(store).use(router).mount('#app')
  1. 新建文件src/directives/index.js
export const lazy = {
    mounted(el, { value }) {
        // 图片的懒加载逻辑
        // 参数1:回调函数
        // 参数2:可选的配置
        const observer = new IntersectionObserver(
            ([{ isIntersecting }], observer) => {
                // isIntersecting为true代表进入可视区
                if (isIntersecting) {
                    // 停止监听
                    observer.unobserve(el)
                    // 给el元素设置src属性
                    // value = '123.jpg'
                    el.src = value
                    // 如果图片加载失败,显示默认的图片
                    el.onerror = function() {
                        el.src = require('@/assets/error.jpg')
                    }
                }
            },
            {
                threshold: 0
            }
        )
        observer.observe(el)
    }
}
  1. 在组件中使用
<template>
  <h1>图片懒加载</h1>
  <div class="box">
    <img v-for="(img, index) in imgList" :key="index"  v-lazy="img">
  </div>
</template>
<script>
import { reactive, toRefs } from 'vue'
import { reqImgList } from '@/api/img'
export default {
  name: 'Home',
  setup () {
    const state = reactive({
      imgList: []
    })
    reqImgList(4).then(res => {
      state.imgList = res.pic
    })
    return {
      ...toRefs(state)
    }
  }
}
</script>
<style lang="less" scoped>
.box {
  display: flex;
  flex-wrap: wrap;
  img {
    width: 400px;
    height: 400px;
  }
}
</style>