// composables/useInfiniteScroll.ts import { ref, onMounted, onBeforeUnmount } from "vue"; export default function useInfiniteScroll( callback: () => Promise, elementId?: string ) { const route = useRoute(); const isFetching = ref(false); const infiniteScroll = ref(null); // Throttle function to limit scroll event frequency const throttle = (func: (...args: any[]) => void, limit: number) => { let lastFunc: ReturnType; let lastRan: number; return function (this: any, ...args: any[]) { const context = this; if (!lastRan) { func.apply(context, args); lastRan = Date.now(); } else { clearTimeout(lastFunc); lastFunc = setTimeout(() => { if (Date.now() - lastRan >= limit) { func.apply(context, args); lastRan = Date.now(); } }, limit - (Date.now() - lastRan)); } }; }; const checkScrollPosition = () => { if (isFetching.value || !infiniteScroll.value) return; let scrollPosition: number; let threshold: number; let clientHeight: number; let scrollHeight: number; if (infiniteScroll.value === window) { scrollPosition = window.scrollY || window.pageYOffset; clientHeight = document.documentElement.clientHeight; scrollHeight = document.documentElement.scrollHeight; } else { const el = infiniteScroll.value as HTMLElement; scrollPosition = el.scrollTop; clientHeight = el.clientHeight; scrollHeight = el.scrollHeight; } threshold = scrollHeight - 100; const currentPosition = scrollPosition + clientHeight; if (currentPosition >= threshold) { isFetching.value = true; callback().finally(() => { isFetching.value = false; }); } }; // Throttled version of scroll handler const throttledScrollHandler = throttle(checkScrollPosition, 200); const handleTouchEnd = () => { setTimeout(throttledScrollHandler, 100); }; onMounted(() => { console.info(route.name) if (route.name == "hadithaSearch" || route.name == "hadithaLibrary") { const targetElement = elementId ? document.getElementById(elementId) : window; if (!targetElement) { console.warn( `Element ${elementId || "window"} not found for infinite scroll` ); return; } infiniteScroll.value = targetElement; if (targetElement === window) { window.addEventListener("scroll", throttledScrollHandler); window.addEventListener("touchend", handleTouchEnd); } else { targetElement.addEventListener("scroll", throttledScrollHandler); targetElement.addEventListener("touchend", handleTouchEnd); } } }); onBeforeUnmount(() => { if (route.name == "hadithaSearch" || route.name == "hadithaLibrary") { if (!infiniteScroll.value) return; if (infiniteScroll.value === window) { window.removeEventListener("scroll", throttledScrollHandler); window.removeEventListener("touchend", handleTouchEnd); } else { (infiniteScroll.value as HTMLElement).removeEventListener( "scroll", throttledScrollHandler ); (infiniteScroll.value as HTMLElement).removeEventListener( "touchend", handleTouchEnd ); } } }); return { isFetching }; }