Vue 3 自定义 Intersection Observer Hook
IntersectionObserver API可以实现对某个DOM元素的可见性检测,它可以检测目标元素是否进入或移出浏览器的可视区域。 这里我们将使用IntersectionObserver封装一个Vue hooks,来实现元素的可见性检测。
IntersectionObserver 实例属性
-
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>