Vue自定义指令+IntersectionObserver实现图片懒加载

小满的视频

代码:
图片储存在/assets/images/文件夹下

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

<script setup lang="ts">
import { Directive } from "vue";
/* import.meta.glob:文件引入,将指定文件夹中的文件一次性全部引入
    1. 此处是通过文件夹把.jpg的图片全部引入,结果是一个对象
    2. 默认为懒加载,加上参数eager:true就是一次全部引入,
*/
let imageList: Record<string, { default: string }> = import.meta.glob(
  "@/assets/images/*.jpg",
  { eager: true }
);
// 所有图片的地址做成一个数组
let arr = Object.keys(imageList);
// 自定义指令,实现懒加载
let vLazy: Directive<HTMLImageElement, string> = async (el, binding) => {
  // import:动态加载资源,返回Promise对象,所以使用await,
  const defaultImg = await import("@/assets/images/x.jpg"); 
  // 先把src的地址设定为未加载时的图片
  el.src = defaultImg.default;
  // IntersectionObserver(交叉观察器)
  const observer = new IntersectionObserver((entries) => {
    if (entries[0].intersectionRatio>0){  // 如果图片出现在屏幕中
      setTimeout(() => {  // 使用定时器时为了更好观察懒加载的效果
      el.src = binding.value  // 加载图片
      observer.unobserve(el)  // 停止观察
      }, 500);
    }
  })
  observer.observe(el); // 开始观察
};
</script>

本章学习到的内容:

1. import.meta.glob

  • 代码:
import.meta.glob(
  "@/assets/images/*.jpg",
  { eager: true }
);

返回的类型:Record<string, { default: string }>

这个Vue函数的作用是使用ES6的模块语法,动态地导入所有位于"@/assets/images/“目录下且文件扩展名为”.jpg"的图片资源。import.meta.glob是Vite(Vue的开发者工具)提供的一个函数,用于实现模式化的资源导入。

import.meta.glob函数接收两个参数:一个字符串模式,用于指定要导入的资源路径模式;一个选项对象,用于控制导入行为。

在这个例子中,字符串"@/assets/images/*.jpg"指定了要导入的图片路径模式,表示导入该目录下所有以".jpg"结尾的文件。

{ eager: true }选项表示立即加载这些图片,而不是在运行时按需加载(懒加载)。这意味着在构建过程中,所有匹配的图片都会被预先加载并包含在最终的构建输出中。

结果是,imageList被赋值为一个对象,其键是匹配的文件路径(相对于项目的根目录),值是一个对象,包含一个default属性,该属性存储了图片的URL路径,可以在模板中直接使用。

import.meta.glob("@/assets/images/*.jpg",);

返回的类型:Record<string, () => Promise<{ default: string }>>

2. Record类型(TS类型)

/**
 * Construct a type with a set of properties K of type T
 * 用一组T类型的属性K构造一个类型
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

示例:

type StringKeys = "a" | "b" | "c";
type MyType = Record<StringKeys  , number>;

// 等价于
type MyType = {
  a: number;
  b: number;
  c: number;
};

MyType 的键必须包含StringKeys 中的所有属性

3. Object.keys()Object.values()Object.entries()

Object.keys()、Object.values()、Object.entries()的用法

let arr = Object.keys(imageList);
把imageList对象中的所有键提出来,重新组成一个数组

4. import(“@/assets/images/x.jpg”);

const defaultImg = await import("@/assets/images/x.jpg");

  1. import:动态加载文件
  2. import("@/assets/images/x.jpg")的返回值是Promise
  3. 想要获得Promise对象成功(fulfilled)后的值,需要使用async…await
  4. fulfilled的返回值是一个对象类型:{default:string}

5. IntersectionObserver交叉观察器

IntersectionObserver一分钟学会,超级简单

使用IntersectionObserver

  1. 创建IntersectionObserver对象,callback中的参数entries是最重要的
const observer = new IntersectionObserver(callback, option);
  const observer = new IntersectionObserver((entries) => {
  
    if (entries[0].intersectionRatio > 0){ //被观察的元素是否可见
	// todo
      observer.unobserve(el)  // 停止观察el元素

  })
  observer.observe(el); // 开始观察el元素
  1. entries[0](在vue3中需要[0]
  • boundingClientRect:目标元素的矩形区域的信息
  • intersectionRatio:目标元素的可见比例,即intersectionRect(被观察的元素)占boundingClientRect(当前可视视窗)的比例,完全可见时为1,完全不可见时小于等于0
  • intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
  • isIntersecting: 布尔值,目标元素与交集观察者的根节点是否相交(常用)
  • isVisible:布尔值,目标元素是否可见(该属性还在试验阶段,不建议在生产环境中使用)
  • rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
  • target:被观察的目标元素,是一个 DOM 节点对象(常用) time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值