代码:
图片储存在/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");
- import:动态加载文件
import("@/assets/images/x.jpg")
的返回值是Promise- 想要获得Promise对象成功(fulfilled)后的值,需要使用async…await
- fulfilled的返回值是一个对象类型:
{default:string}
5. IntersectionObserver交叉观察器
IntersectionObserver一分钟学会,超级简单
使用IntersectionObserver
- 创建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元素
entries[0]
(在vue3中需要[0]
)
boundingClientRect
:目标元素的矩形区域的信息intersectionRatio
:目标元素的可见比例,即intersectionRect(被观察的元素)占boundingClientRect(当前可视视窗)的比例,完全可见时为1,完全不可见时小于等于0intersectionRect
:目标元素与视口(或根元素)的交叉区域的信息isIntersecting
: 布尔值,目标元素与交集观察者的根节点是否相交(常用)isVisible
:布尔值,目标元素是否可见(该属性还在试验阶段,不建议在生产环境中使用)rootBounds
:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回nulltarget
:被观察的目标元素,是一个 DOM 节点对象(常用) time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒