IntersectionObserver
2024-04-09 本文已影响0人
Peter_2B
图片懒加载
<template>
<div style="overflow-y: auto">
<img v-lazy="it" width="375" height="400" v-for="it of imgArr" />
</div>
</template>
<script setup>
// 引入所有静态文件 glob引入默认是懒加载模式,eager:true 静态加载,否则是懒加载;
let imgList = import.meta.glob("../assets/images/*.*", { eager: true });
let imgArr = Object.values(imgList).map((i) => i.default);
let vLazy = async (el, binding) => {
// 1.先设置默认展位图片
const defaultImg = await import("../assets/vue.svg");
el.src = defaultImg.default;
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
el.src = binding.value;
observer.unobserve(el); // 取消监听元素
}
});
observer.observe(el); // 开始监听某个元素
};
</script>
元素滑动进入视图
// vSlideAnimation.js
const DISTANCE = 100;
const DURATION = 200;
const map = new WeakMap();
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const animation = map.get(entry.target);
animation && animation.play();
observer.unobserve(entry.target);
}
});
});
// 获取元素是否在视口内
function isInnerViewport(el) {
// 获取元素相对于视口的距离信息对象
const rect = el.getBoundingClientRect();
// 元素的上边距离减去视口高度是否大于0, 在视口上方的距离大于视口高度,则元素不在视口内
return rect.top - window.innerHeight > 0;
}
export const vSlideAnimation = {
mounted(el) {
if (!isInnerViewport(el)) return;
// 给元素设置动画对象,并返回动画对象实例
const animation = el.animate(
[
{ transform: `translateY(${DISTANCE}px)` },
{ transform: "translateY(0)" },
],
{
duration: DURATION,
ease: "ease",
fill: "forwards",
}
);
animation.pause();
observer.observe(el);
map.set(el, animation);
},
onMounted(el) {
observer.disconnect(el);
},
};