2024-06-14 16:17:22 +00:00
|
|
|
import { useNuxtApp } from './nuxt'
|
2024-06-14 16:44:13 +00:00
|
|
|
import defu from 'defu'
|
2024-06-14 16:17:22 +00:00
|
|
|
|
2024-06-14 16:46:41 +00:00
|
|
|
/** @since 3.9.0 */
|
2023-12-23 14:22:58 +00:00
|
|
|
export function toArray<T> (value: T | T[]): T[] {
|
|
|
|
return Array.isArray(value) ? value : [value]
|
|
|
|
}
|
2024-03-25 13:07:52 +00:00
|
|
|
|
2024-06-14 15:31:21 +00:00
|
|
|
export type CallbackFn = () => void
|
|
|
|
export type ObserveFn = (element: Element, callback: CallbackFn) => () => void
|
2024-06-14 16:17:22 +00:00
|
|
|
|
2024-06-14 16:44:13 +00:00
|
|
|
export function useIntersectionObserver (options?: Partial<IntersectionObserverInit>): { observe: ObserveFn } {
|
2024-06-14 16:17:22 +00:00
|
|
|
if (import.meta.server) { return {observe: () => () => {}} }
|
|
|
|
|
|
|
|
const nuxtApp = useNuxtApp()
|
|
|
|
if (nuxtApp._observer) {
|
|
|
|
return nuxtApp._observer
|
|
|
|
}
|
|
|
|
|
|
|
|
let observer: IntersectionObserver | null = null
|
|
|
|
const callbacks = new Map<Element, CallbackFn>()
|
|
|
|
|
|
|
|
const observe: ObserveFn = (element, callback) => {
|
|
|
|
if (!observer) {
|
|
|
|
observer = new IntersectionObserver((entries) => {
|
|
|
|
for (const entry of entries) {
|
|
|
|
const callback = callbacks.get(entry.target)
|
|
|
|
const isVisible = entry.isIntersecting || entry.intersectionRatio > 0
|
|
|
|
if (isVisible && callback) { callback() }
|
|
|
|
}
|
2024-06-14 16:45:38 +00:00
|
|
|
}, defu(options ?? {},{root: null, rootMargin: "0px", threshold: 0}))
|
2024-06-14 16:17:22 +00:00
|
|
|
}
|
|
|
|
callbacks.set(element, callback)
|
|
|
|
observer.observe(element)
|
|
|
|
return () => {
|
|
|
|
callbacks.delete(element)
|
|
|
|
observer!.unobserve(element)
|
|
|
|
if (callbacks.size === 0) {
|
|
|
|
observer!.disconnect()
|
|
|
|
observer = null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const _observer = nuxtApp._observer = {
|
|
|
|
observe,
|
|
|
|
}
|
|
|
|
|
|
|
|
return _observer
|
2024-06-14 16:24:13 +00:00
|
|
|
}
|