feat: Enhance infinite scroll functionality with improved observer settings and scroll event handling

This commit is contained in:
Will Miao
2025-04-13 17:58:14 +08:00
parent 72c6f91130
commit fa27513f76
3 changed files with 42 additions and 39 deletions

View File

@@ -48,6 +48,7 @@ export function initializeInfiniteScroll(pageType = 'loras') {
const debouncedLoadMore = debounce(loadMoreFunction, 100); const debouncedLoadMore = debounce(loadMoreFunction, 100);
// Create a more robust observer with lower threshold and root margin
state.observer = new IntersectionObserver( state.observer = new IntersectionObserver(
(entries) => { (entries) => {
const target = entries[0]; const target = entries[0];
@@ -55,7 +56,10 @@ export function initializeInfiniteScroll(pageType = 'loras') {
debouncedLoadMore(); debouncedLoadMore();
} }
}, },
{ threshold: 0.1 } {
threshold: 0.01, // Lower threshold to detect even minimal visibility
rootMargin: '0px 0px 300px 0px' // Increase bottom margin to trigger earlier
}
); );
const grid = document.getElementById(gridId); const grid = document.getElementById(gridId);
@@ -71,14 +75,14 @@ export function initializeInfiniteScroll(pageType = 'loras') {
// Create a wrapper div that will be placed after the grid // Create a wrapper div that will be placed after the grid
const sentinelWrapper = document.createElement('div'); const sentinelWrapper = document.createElement('div');
sentinelWrapper.style.width = '100%'; sentinelWrapper.style.width = '100%';
sentinelWrapper.style.height = '10px'; sentinelWrapper.style.height = '30px'; // Increased height for better visibility
sentinelWrapper.style.margin = '0'; sentinelWrapper.style.margin = '0';
sentinelWrapper.style.padding = '0'; sentinelWrapper.style.padding = '0';
// Create the actual sentinel element // Create the actual sentinel element
const sentinel = document.createElement('div'); const sentinel = document.createElement('div');
sentinel.id = 'scroll-sentinel'; sentinel.id = 'scroll-sentinel';
sentinel.style.height = '10px'; sentinel.style.height = '30px'; // Match wrapper height
// Add the sentinel to the wrapper // Add the sentinel to the wrapper
sentinelWrapper.appendChild(sentinel); sentinelWrapper.appendChild(sentinel);
@@ -88,4 +92,37 @@ export function initializeInfiniteScroll(pageType = 'loras') {
state.observer.observe(sentinel); state.observer.observe(sentinel);
} }
// Add a scroll event backup to handle edge cases
const handleScroll = debounce(() => {
if (pageState.isLoading || !pageState.hasMore) return;
const sentinel = document.getElementById('scroll-sentinel');
if (!sentinel) return;
const rect = sentinel.getBoundingClientRect();
const windowHeight = window.innerHeight;
// If sentinel is within 500px of viewport bottom, load more
if (rect.top < windowHeight + 500) {
debouncedLoadMore();
}
}, 200);
// Clean up existing scroll listener if any
if (state.scrollHandler) {
window.removeEventListener('scroll', state.scrollHandler);
}
// Save reference to the handler for cleanup
state.scrollHandler = handleScroll;
window.addEventListener('scroll', state.scrollHandler);
// Check position immediately in case content is already visible
setTimeout(() => {
const sentinel = document.getElementById('scroll-sentinel');
if (sentinel && sentinel.getBoundingClientRect().top < window.innerHeight) {
debouncedLoadMore();
}
}, 100);
} }

View File

@@ -1,38 +1,7 @@
<!-- Checkpoint Modals --> <!-- Checkpoint Modals -->
<!-- Delete Confirmation Modal -->
<div id="deleteConfirmModal" class="modal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h2>Confirm Delete</h2>
<span class="close">&times;</span>
</div>
<div class="modal-body">
<p id="deleteConfirmMessage">Are you sure you want to delete this checkpoint?</p>
</div>
<div class="modal-footer">
<button id="cancelDeleteBtn" class="btn btn-secondary">Cancel</button>
<button id="confirmDeleteBtn" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
<!-- Checkpoint Details Modal (to be implemented in the future) --> <!-- Checkpoint details Modal -->
<div id="checkpointModal" class="modal" style="display: none;"> <div id="checkpointModal" class="modal"></div>
<div class="modal-content modal-large">
<div class="modal-header">
<h2 id="checkpointModalTitle">Checkpoint Details</h2>
<span class="close">&times;</span>
</div>
<div class="modal-body">
<div id="checkpointModalContent">
<!-- Content will be dynamically added here -->
<div class="placeholder-message">
<p>Checkpoint details will be displayed here.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Download Checkpoint from URL Modal --> <!-- Download Checkpoint from URL Modal -->
<div id="checkpointDownloadModal" class="modal"> <div id="checkpointDownloadModal" class="modal">

View File

@@ -1,9 +1,6 @@
<!-- Model details Modal --> <!-- Model details Modal -->
<div id="loraModal" class="modal"></div> <div id="loraModal" class="modal"></div>
<!-- Checkpoint details Modal -->
<div id="checkpointModal" class="modal"></div>
<!-- Download from URL Modal (for LoRAs) --> <!-- Download from URL Modal (for LoRAs) -->
<div id="downloadModal" class="modal"> <div id="downloadModal" class="modal">
<div class="modal-content"> <div class="modal-content">