在现代网页设计中,提供流畅且具有交互性的用户体验至关重要。监听元素进出视图的变化是实现这一目标的常见任务,但往往涉及繁琐的代码编写。为了简化这一过程,编写出了 useMultiIntersectionObserver 自定义 Hook,它能够轻松地监听元素的可见性变化。
介绍
useMultiIntersectionObserver 是一个自定义 Hook,用于监听一个或多个元素是否出现在视图中。它基于 Intersection Observer API,并封装了常用的功能,简化了代码编写过程。通过使用 useMultiIntersectionObserver,开发人员可以专注于实现各种交互效果,如图片懒加载和无限滚动,而无需过多关注底层的 Intersection Observer 实现细节。
使用方法
安装
首先,我们需要安装 st-multi-intersection-observer
包。在命令行中执行以下命令:
npm i st-multi-intersection-observer
引入与使用
引入 useMultiIntersectionObserver
:
import { useMultiIntersectionObserver } from 'st-multi-intersection-observer';
const multiIntersectionObserver = useMultiIntersectionObserver( dom/dom数组 , 回调事件 , IntersectionObserver配置参数(可不传) )
multiIntersectionObserver.unobserveElement() // unobserveElement 单个移除某个dom的监听事件
multiIntersectionObserver.unobserveAllElements() // unobserveAllElements 停止观察所有元素
multiIntersectionObserver.disconnectObserver() // unobserveAllElements disconnectObserver 关闭观察器
使用实例
图片懒加载
使用 useMultiIntersectionObserver,我们可以轻松实现图片懒加载的效果。
<template>
<div>
<img v-for="image in images" :key="image.src" class="lazy-image" :data-src="image.src" />
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useMultiIntersectionObserver } from '@/hooks/useMultiIntersectionObserver';
export default {
setup() {
const images = ref([
{ src: 'path/to/image1.jpg' },
{ src: 'path/to/image2.jpg' },
{ src: 'path/to/image3.jpg' }
]);
onMounted(() => {
const { unobserveElement } = useMultiIntersectionObserver(document.querySelectorAll('.lazy-image'), (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src;
unobserveElement(entry.target);
}
});
},{});
});
return {
images,
};
},
};
</script>
在上面的示例中,我们通过使用 useMultiIntersectionObserver
自定义 Hook 来监听带有 lazy-image
类名的图片元素的可见性变化。当图片元素进入视图时,将其 data-src
属性的值赋给 src
属性,实现图片的延迟加载效果。需要注意的是,确保在 img
元素上设置了 data-src
属性来存储真实的图片路径。
无限滚动
另一个常见的应用场景是实现无限滚动。通过监听滚动容器的底部元素是否进入视图,我们可以触发加载更多数据的逻辑,从而实现无限滚动的效果。
<template>
<div ref="container" style="height: 500px; overflow-y: scroll;">
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
<li ref="scrollEnd"></li>
</ul>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useMultiIntersectionObserver } from '@/hooks/useMultiIntersectionObserver';
export default {
setup() {
const items = ref(['Item 1', 'Item 2', 'Item 3']); // 初始数据
const scrollEnd = ref(null);
onMounted(() => {
const { unobserveElement } = useMultiIntersectionObserver(scrollEnd.value, (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 触发加载更多数据的逻辑
loadMoreData()
}
});
}, {});
});
const loadMoreData = () => {
// 模拟异步加载更多数据
setTimeout(() => {
const newItems = ['Item 4', 'Item 5', 'Item 6']; // 新加载的数据
items.value = [...items.value, ...newItems];
}, 1000);
};
return {
items,
};
},
};
</script>
在上面的示例中,我们使用了 useMultiIntersectionObserver
自定义 Hook 来监听滚动容器底部元素 scrollEnd
的可见性变化。当底部元素进入视图时,会触发 loadMoreData
函数,该函数模拟异步加载更多数据,并将新数据追加到 items
数组中,实现了无限滚动的效果。请确保在滚动容器的 CSS 样式中设置了固定的高度和合适的滚动属性。
代码实现
让我们来逐步介绍 useMultiIntersectionObserver 的代码实现。
首先,定义了一个函数,命名为 useMultiIntersectionObserver,该函数接收三个参数:elements、options 和 callback。
export function useMultiIntersectionObserver(elements, callback,options = {} ) {
// ...
}
- elements:表示要监听的元素,可以是单个元素或元素数组。
- options:表示 IntersectionObserver 的配置参数,可选。
- callback:表示元素进出视图时的回调函数,可选。
接下来,我们需要进行参数验证。如果 elements 参数为空或为一个空数组,则抛出错误。
if (!elements || (Array.isArray(elements) && elements.length === 0)) {
throw new Error('参数 elements 不能为空');
}
然后,我们需要判断 elements 是单个元素还是元素数组,并将其统一转为数组形式。
const isSingleElement = !Array.isArray(elements);
const targetElements = isSingleElement ? [elements] : elements;
接下来,我们创建一个 IntersectionObserver 实例对象,传入回调函数和配置参数。
const observer = new IntersectionObserver((entries, observer) => {
callback && callback(entries, observer);
}, options);
在创建实例后,我们需要开始监听 DOM 变化。遍历 targetElements 数组,并对每个元素调用 observe 方法。
targetElements.forEach((element) => {
observer.observe(element);
});
在这里,我们已经完成了 useMultiIntersectionObserver 的主要实现部分。
停止观察某个元素
如果我们想停止观察特定的元素,可以使用 unobserveElement 方法。该方法接收一个参数 element,表示要停止观察的 DOM 元素。
const unobserveElement = (element) => {
if (element) {
observer.unobserve(element);
}
};
停止观察所有元素
如果我们想停止观察所有元素,可以使用 unobserveAllElements 方法。
const unobserveAllElements = () => {
targetElements.forEach((element) => {
observer.unobserve(element);
});
};
关闭观察器
如果我们想完全关闭观察器,可以使用 disconnectObserver 方法。
const disconnectObserver = () => {
observer.disconnect();
};
最后,我们需要返回这些方法作为结果。
return {
unobserveElement,
unobserveAllElements,
disconnectObserver,
};
完整代码
下面是 useMultiIntersectionObserver 的完整代码实现:
export function useMultiIntersectionObserver(elements, callback,options = {} ) {
if (!elements || (Array.isArray(elements) && elements.length === 0)) {
throw new Error('参数 elements 不能为空');
}
const isSingleElement = !Array.isArray(elements);
const targetElements = isSingleElement ? [elements] : elements;
const observer = new IntersectionObserver((entries, observer) => {
callback && callback(entries, observer);
}, options);
targetElements.forEach((element) => {
observer.observe(element);
});
const unobserveElement = (element) => {
if (element) {
observer.unobserve(element);
}
};
const unobserveAllElements = () => {
targetElements.forEach((element) => {
observer.unobserve(element);
});
};
const disconnectObserver = () => {
observer.disconnect();
};
return {
unobserveElement,
unobserveAllElements,
disconnectObserver,
};
}
特点
- 简化代码:useMultiIntersectionObserver 封装了底层的 Intersection Observer 实现细节,使代码更加简洁和易于理解。
- 灵活可配置:通过 options 参数,您可以自定义 Intersection Observer 的配置,以满足不同的需求。
- 适用于多种场景:useMultiIntersectionObserver 可以应用于图片懒加载、无限滚动等多种场景,提供了更好的交互体验。
结语
通过使用 useMultiIntersectionObserver 自定义 Hook,我们可以轻松地监听元素的可见性变化,从而实现各种交互效果。无论是图片懒加载还是无限滚动,它都为我们提供了简单且灵活的解决方案。希望本文对您理解和使用 useMultiIntersectionObserver 有所帮助,并为提升网页交互体验提供了新的思路。
让我们一起解放双手,优化前端开发!