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);
  },
};
上一篇下一篇

猜你喜欢

热点阅读