实现图片懒加载的5种方式

目录

1、懒加载介绍

2、实现懒加载技术的方案

3、具体实现代码


1、懒加载介绍

当页面需要展示大量图片时,如果一次性渲染所有图片,会向服务器发出大量请求,导致服务器响应慢,出现页面卡顿或崩溃等问题。用懒加载技术只预先加载可视区内的图片,当滚动到其他位置时,才去加载这块区域的图片,也可以使用比较小的loading图片进行占位,有效减轻服务器的压力,加速页面渲染,提高用户体验。

2、实现懒加载技术的方案

(1)使用element-ui 的<el-image v-for="url in urls" :key="url" :src="url" lazy></el-iamge>可通过lazy开启懒加载功能,当图片滚动到可视范围内才会加载。

(2)使用vue-lazyLoad插件实现

(3)使用IntersectionObserver Api监听某些节点是否出现在可视区域内。

(4)offsetTop(图像距离顶部的高度)-scrollTop(页面被卷去的高度)<=window.innerHeight(可视区高度)才加载

(5)获得页面中某个元素的上边相对浏览器视窗的位置getBoundingClientRect().top<=window.innerHeight(可视区高度)才加载

3、具体实现代码

(1)element-ui <el-image> Element - The world's most popular Vue UI framework

(2)使用vue-lazyLoad插件实现,安装【npm i vue-lazyload -S】,main.ts中进行注册

//main.ts
import VueLazyload from 'vue-lazyload'
app.use(VueLazyload,
    {preLoad: 1.3, //预加载的宽高比loading: 
    loadimage:"./assets/vue.svg", //图片加载状态下显示的图片
    // error: "", //图片加载失败时显示的图片
    attempt: 1, // 加载错误后最大尝试次数
})

页面中通过v-lazy使用

//xx.vue
<template>
  <div>
    <div v-for="item in arr" :key="item">
      <img v-lazy="item" width="600" height="200" alt="" />
    </div>
  </div>
</template>

<script lang="ts" setup>
//glob是懒加载模式,globEager静态加载
let imageList: Record<string, { default: string }> = import.meta.glob(
  "../assets/images/*.*",
  { eager: true }
);
let arr = Object.values(imageList).map((v) => v.default);
</script>

<style lang="scss" scoped></style>
使用vite的两种文件导入方式
  • 【import.meta.glob("/xx")】方式 为懒加载模式,动态导入,构建时,会分离为独立的 chunk,该方式导入使用()=>import("/xx"),跟路由懒加载是一样的导入方式。
  • 【import.meta.globEager("/xx")】以及【import.meta.glob("/xx",{eager:true})】为静态加载

 打印imageList如图

 (3)使用IntersectionObserver Api监听某些节点是否出现在可视区域内。

intersectionRatio表示节点出现在可视区的比例,isIntersecting为布尔值,为true表示出现在可视区

<template>
  <div>
    <div v-for="item in arr" :key="item">
      <img v-lazy="item" width="600" height="200" alt="" />
    </div>
  </div>
</template>

<script lang="ts" setup>
import type { Directive } from "vue";
//glob是懒加载模式,globEager静态加载
let imageList: Record<string, { default: string }> = import.meta.glob(
  "../assets/images/*.*",
  { eager: true }
);
console.log(">>>>>>>>>>>>>>>imageList", imageList);
let arr = Object.values(imageList).map((v) => v.default);
console.log(arr);
// 使用自定义指令
let vLazy: Directive<HTMLImageElement, string> = async (el, bingding) => {
  let url = await import("../assets/vue.svg");
  el.src = url.default;
  let observer = new IntersectionObserver((entry) => {
    console.log(entry[0], el);
    if (entry[0].intersectionRatio > 0 && entry[0].isIntersecting) {
      el.src = bingding.value;
      observer.unobserve(el);//停止监听el对象
    }
  });
  observer.observe(el); //开启监听el对象
};
</script>

<style lang="scss" scoped></style>

(4)判断图像的offsetTop(距离顶部的高度)-scrollTop(页面被卷去的高度)<=window.innerHeight(可视区高度)才加载

<template>
  <div>
    <div v-for="item in arr" :key="item">
      <img
        ref="img"
        :data-src="item"
        src="../assets/vue.svg"
        width="600"
        height="200"
        alt=""
      />
    </div>
  </div>
</template>

<script lang="ts" setup>
import { onMounted } from "vue";

//glob是懒加载模式,globEager静态加载
let imageList: Record<string, { default: string }> = import.meta.glob(
  "../assets/images/*.*",
  { eager: true }
);
let arr = Object.values(imageList).map((v) => v.default);
const winHeight = window.innerHeight; // 浏览器可视区的高度

onMounted(() => {
  var imgs = document.querySelectorAll("img");
  let num = Math.ceil(winHeight / 200);
  loadImg(imgs, 0, num); //   1.只加载可视区域内的图片-适用于图片高度固定的场景
  window.addEventListener("scroll", function () {
    loadImg(imgs, num, imgs.length); // 2.滚动时加载其他未加载的图片
  });
});
function loadImg(img, startIdx, num) {
  for (let i = startIdx; i < num; i++) {
    if (startIdx == 0) {
      img[i].src = img[i].dataset.src;
    } else {
      var imgOffsetTop = img[i].offsetTop; // 图片距顶部的高度
      var scrollTop = document.documentElement.scrollTop; // 页面被卷去的高度
      if (imgOffsetTop - scrollTop <= winHeight) {
        // 判断图片是否将要出现
        img[i].src = img[i].dataset.src; // 出现后将自定义地址转为真实地址
      }
    }
  }
}
</script>

(5)获得页面中某个元素的上边相对浏览器视窗的位置getBoundingClientRect().top<=window.innerHeight(可视区高度)才加载

<template>
  <div>
    <div v-for="item in arr" :key="item">
      <img
        ref="img"
        :data-src="item"
        src="../assets/vue.svg"
        width="600"
        height="200"
        alt=""
      />
    </div>
  </div>
</template>

<script lang="ts" setup>
import { onMounted, ref } from "vue";
let timer = ref<number>(0);
//glob是懒加载模式,globEager静态加载
let imageList: Record<string, { default: string }> = import.meta.glob(
  "../assets/images/*.*",
  { eager: true }
);
console.log(imageList);

let arr = Object.values(imageList).map((v) => v.default);
const winHeight = window.innerHeight; // 浏览器可视区的高度

onMounted(() => {
  var imgs = document.querySelectorAll("img");
  let num = Math.ceil(winHeight / 200);
  loadImg(imgs, 0, num); //   1.只加载可视区域内的图片-适用于图片高度固定的场景
  window.addEventListener("scroll", (e) => {
    loadImg(imgs, num, imgs.length); // 2.滚动时加载其他未加载的图片
  });
});

function loadImg(img, startIdx, num) {
  for (let i = startIdx; i < num; i++) {
    if (startIdx == 0) {
      img[i].src = img[i].dataset.src;
    } else {
      const rect = img[i].getBoundingClientRect(); //getBoundingClientRect()用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。
      if (rect.top < window.innerHeight) {
        img[i].src = img[i].dataset.src;
      }
    }
  }
}
</script>

注意:获取元素节点要放在onMounted钩子中,因此此时Dom才挂载完成

  • 1
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值