82 lines
2.0 KiB
TypeScript
82 lines
2.0 KiB
TypeScript
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
|
|
|
/**
|
|
* Reusable Infinite Scroll Composable
|
|
* @param {import('vue').Ref<Array>} sourceData - The full source array of data
|
|
* @param {number} pageSize - Number of items to load per "page"
|
|
* @param {Object} options - Additional options
|
|
* @returns {Object} { visibleItems, targetRef, loadMore, reset }
|
|
*/
|
|
export function useInfiniteScroll(sourceData, pageSize = 20, options = {}) {
|
|
const visibleCount = ref(pageSize);
|
|
const targetRef = ref(null);
|
|
|
|
// Compute visible items based on current count
|
|
const visibleItems = computed(() => {
|
|
const data = sourceData.value || [];
|
|
return data.slice(0, visibleCount.value);
|
|
});
|
|
|
|
// Check if there are more items to load
|
|
const hasMore = computed(() => {
|
|
const data = sourceData.value || [];
|
|
return visibleCount.value < data.length;
|
|
});
|
|
|
|
const loadMore = () => {
|
|
if (hasMore.value) {
|
|
visibleCount.value += pageSize;
|
|
}
|
|
};
|
|
|
|
const reset = () => {
|
|
visibleCount.value = pageSize;
|
|
};
|
|
|
|
// Setup IntersectionObserver
|
|
let observer = null;
|
|
|
|
onMounted(() => {
|
|
observer = new IntersectionObserver((entries) => {
|
|
const entry = entries[0];
|
|
if (entry.isIntersecting && hasMore.value) {
|
|
loadMore();
|
|
}
|
|
}, {
|
|
root: null,
|
|
rootMargin: '100px', // Preload before reaching bottom
|
|
threshold: 0.1,
|
|
...options
|
|
});
|
|
|
|
if (targetRef.value) {
|
|
observer.observe(targetRef.value);
|
|
}
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (observer) observer.disconnect();
|
|
});
|
|
|
|
// Watch for targetRef changes (e.g., if valid status changes)
|
|
watch(targetRef, (el) => {
|
|
if (observer) {
|
|
observer.disconnect();
|
|
if (el) observer.observe(el);
|
|
}
|
|
});
|
|
|
|
// Reset when source data changes significantly (optional, depending on use case)
|
|
// watch(sourceData, () => {
|
|
// reset(); // Uncomment if you want to reset scroll on data refresh
|
|
// });
|
|
|
|
return {
|
|
visibleItems,
|
|
targetRef,
|
|
loadMore,
|
|
reset,
|
|
hasMore
|
|
};
|
|
}
|