使用vue3+ts来封装一个实时监视元素是否在可视窗口内的hooks,适用于web平台(pc、h5),实时监测

294 阅读2分钟

Vue 3 自定义 Intersection Observer Hook

IntersectionObserver API可以实现对某个DOM元素的可见性检测,它可以检测目标元素是否进入或移出浏览器的可视区域。 这里我们将使用IntersectionObserver封装一个Vue hooks,来实现元素的可见性检测。

IntersectionObserver 实例属性

  • IntersectionObserver.root 只读

    测试交叉时,用作边界盒的元素文档。如果构造函数未传入 root 或其值为null,则默认使用顶级文档的视口。

  • IntersectionObserver.rootMargin 只读

    计算交叉时添加到根边界盒 (en-US)的矩形偏移量,可以有效的缩小或扩大根的判定范围从而满足计算需要。此属性返回的值可能与调用构造函数时指定的值不同,因此可能需要更改该值,以匹配内部要求。所有的偏移量均可用像素px)或百分比%)来表达,默认值为“0px 0px 0px 0px”。

  • IntersectionObserver.thresholds (en-US) 只读

    一个包含阈值的列表,按升序排列,列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会生成一个通知(Notification)。如果构造器未传入值,则默认值为 0。

Hook 定义

import { ref, onMounted, onUnmounted } from "vue";

// 定义IntersectionObserver的配置选项接口
interface IntersectionOptions {
  root?: Element | null; // 被监听元素的根元素,默认为浏览器视窗
  rootMargin?: string; // root边界的扩展区
  threshold?: number | number[]; // 交叉界线的阈值,可以是数字或数组
}

// 自定义IntersectionObserver hook函数
const useIntersectionObserver = (
  // 被监听的DOM元素
  target: Ref<Element | null>,

  // IntersectionObserver的配置选项
  options?: IntersectionOptions
) => {
  // 定义一个ref来保存当前元素是否在视口内可见,默认false
  const isVisible = ref(false);

  // IntersectionObserver的回调函数
  const callback: IntersectionObserverCallback = (entries, observer) => {
    // 对每个进入的元素执行回调
    entries.forEach(entry => {
      // 如果元素进入视口(可见)
      if (entry.isIntersecting) {
        isVisible.value = true;

        // 如果元素移出视口(不可见)
      } else {
        isVisible.value = false;
      }
    });
  };

  // 创建IntersectionObserver实例
  const observer = new IntersectionObserver(callback, options);

  // 在组件挂载时
  onMounted(() => {
    if (target.value) {
      // 开始观察目标元素
      observer.observe(target.value);
    }
  });

  // 在组件卸载时
  onUnmounted(() => {
    if (target.value) {
      // 停止观察
      observer.unobserve(target.value);
    }
  });

  // 返回是否可见的ref
  return isVisible;
};

// 导出这个自定义hook
export default useIntersectionObserver;

使用示例

<template>
  <div class="page-container">
    <div class="glass"></div>
    <div ref="targetElementRef" class="target-element">我是测试元素</div>
  </div>
</template>
<script setup lang="ts">
import useIntersectionObserver from '@/hooks/useIntersectionObserver'

const targetElementRef = ref<HTMLElement | null>(null)
const targetElementRefIsVisibility = useIntersectionObserver(targetElementRef, {
  threshold: 1
})
// 监听元素是否可见
watch(targetElementRefIsVisibility, (val) => {
  console.log('targetElementRefIsVisibility', val)
})
</script>

<style scoped lang="scss">
.page-container {
  background-color: skyblue;
}
.glass {
  width: 100px;
  height: 1000px;
}
.target-element {
  background-color: pink;
  height: 100px;
}
</style>

效果演示

图片.png

1693289047(1).jpg