diff --git a/packages/nuxt/src/app/components/nuxt-link.ts b/packages/nuxt/src/app/components/nuxt-link.ts index c85c60ae17..c714abc310 100644 --- a/packages/nuxt/src/app/components/nuxt-link.ts +++ b/packages/nuxt/src/app/components/nuxt-link.ts @@ -14,7 +14,7 @@ import { onNuxtReady } from '../composables/ready' import { navigateTo, useRouter } from '../composables/router' import { useNuxtApp, useRuntimeConfig } from '../nuxt' import { cancelIdleCallback, requestIdleCallback } from '../compat/idle-callback' -import type { CallbackFn, ObserveFn } from '../utils' +import { useIntersectionObserver } from '../utils' // @ts-expect-error virtual file import { nuxtLinkDefaults } from '#build/nuxt.config.mjs' @@ -306,7 +306,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) { let idleId: number let unobserve: (() => void) | null = null onMounted(() => { - const observer = useObserver() + const observer = useIntersectionObserver() onNuxtReady(() => { idleId = requestIdleCallback(() => { if (el?.value?.tagName) { @@ -445,47 +445,6 @@ function applyTrailingSlashBehavior (to: string, trailingSlash: NuxtLinkOptions[ // --- Prefetching utils --- -function useObserver (): { observe: ObserveFn } | undefined { - if (import.meta.server) { return } - - const nuxtApp = useNuxtApp() - if (nuxtApp._observer) { - return nuxtApp._observer - } - - let observer: IntersectionObserver | null = null - - const callbacks = new Map() - - 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() } - } - }) - } - 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 -} - function isSlowConnection () { if (import.meta.server) { return } diff --git a/packages/nuxt/src/app/utils.ts b/packages/nuxt/src/app/utils.ts index 237f51e6ce..497542451f 100644 --- a/packages/nuxt/src/app/utils.ts +++ b/packages/nuxt/src/app/utils.ts @@ -1,6 +1,50 @@ +import { useNuxtApp } from './nuxt' + + export function toArray (value: T | T[]): T[] { return Array.isArray(value) ? value : [value] } export type CallbackFn = () => void export type ObserveFn = (element: Element, callback: CallbackFn) => () => void + +export function useIntersectionObserver (options?: IntersectionObserverInit): { observe: ObserveFn } { + if (import.meta.server) { return {observe: () => () => {}} } + + const nuxtApp = useNuxtApp() + if (nuxtApp._observer) { + return nuxtApp._observer + } + + let observer: IntersectionObserver | null = null + + const callbacks = new Map() + + 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() } + } + },options) + } + 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 +} \ No newline at end of file diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 20e71125e6..38f4ad4b73 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -6,35 +6,7 @@ import { getFragmentHTML } from '#app/components/utils' import { useNuxtApp } from '#app/nuxt' import { cancelIdleCallback, requestIdleCallback } from '#app/compat/idle-callback' import { onNuxtReady } from '#app' - -function useIntersectionObserver (options: IntersectionObserverInit): { observe: ObserveFn } { - if (import.meta.server) { return { observe: () => () => {} } } - - let observer: IntersectionObserver | null = null - - const observe: ObserveFn = (element, callback) => { - if (!observer) { - observer = new IntersectionObserver((entries) => { - for (const entry of entries) { - const isVisible = entry.isIntersecting || entry.intersectionRatio > 0 - if (isVisible && callback) { callback() } - } - }, options) - } - observer.observe(element) - return () => { - observer!.unobserve(element) - observer!.disconnect() - observer = null - } - } - - const _observer = { - observe, - } - - return _observer -} +import { useIntersectionObserver } from '#app/utils' function elementIsVisibleInViewport (el: Element) { const { top, left, bottom, right } = el.getBoundingClientRect()