window.initInfiniteScroll = function() {
// Configuration
const containerSelector = '.posts';
const itemSelector = '.post';
const paginationSelector = '.pagination';
const nextLinkSelector = '.pagination .page-next .next';
const loadingText = '加载中...';
const noMoreText = '没有更多了';
const container = document.querySelector(containerSelector);
if (!container) return; // Not on a page with posts
// Check if we already have an observer (to prevent duplicates on PJAX re-init)
if (window.infiniteScrollObserver) {
window.infiniteScrollObserver.disconnect();
window.infiniteScrollObserver = null;
}
// Remove existing sentinel if any
const existingSentinel = document.getElementById('infinite-scroll-sentinel');
if (existingSentinel) existingSentinel.remove();
// Find next link
let nextLink = document.querySelector(nextLinkSelector);
if (!nextLink) return; // No next page
// Hide default pagination
const pagination = document.querySelector(paginationSelector);
if (pagination) pagination.style.display = 'none';
// Create sentinel
const sentinel = document.createElement('div');
sentinel.id = 'infinite-scroll-sentinel';
sentinel.innerHTML = `
${loadingText}
`;
// Insert after container
container.parentNode.insertBefore(sentinel, container.nextSibling);
let isLoading = false;
const loadNextPage = async () => {
if (isLoading) return;
// Re-check next link from the DOM (it should be updated after previous fetch)
nextLink = document.querySelector(nextLinkSelector);
if (!nextLink) {
sentinel.innerHTML = `${noMoreText}
`;
if (window.infiniteScrollObserver) window.infiniteScrollObserver.disconnect();
return;
}
isLoading = true;
const url = nextLink.href;
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Network response was not ok');
const text = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(text, 'text/html');
// 1. Get new posts
const newPosts = doc.querySelectorAll(`${containerSelector} ${itemSelector}`);
// 2. Append posts
if (newPosts.length > 0) {
newPosts.forEach(post => {
// Remove UIkit scrollspy attributes to prevent interference and use manual animation
post.removeAttribute('uk-scrollspy-class');
post.style.opacity = 0;
container.appendChild(post);
// Trigger reflow
void post.offsetWidth;
post.style.transition = 'opacity 0.5s ease';
post.style.opacity = 1;
});
}
// 3. Update pagination (crucial for next link)
const newPagination = doc.querySelector(paginationSelector);
const oldPagination = document.querySelector(paginationSelector);
if (oldPagination && newPagination) {
oldPagination.innerHTML = newPagination.innerHTML;
oldPagination.style.display = 'none'; // Keep hidden
} else if (oldPagination && !newPagination) {
oldPagination.remove();
sentinel.innerHTML = `${noMoreText}
`;
if (window.infiniteScrollObserver) window.infiniteScrollObserver.disconnect();
isLoading = false;
return;
}
// 4. Re-init plugins for new content
if (typeof lazyLoadInit === 'function') {
lazyLoadInit({
offsetBottom: 800,
offsetTopm: 800,
showTime: 1100
});
}
if (window.ViewImage) {
ViewImage.init('.post-content img');
}
// 5. Check if there is a next page in the NEW content (double check)
const newNextLink = document.querySelector(nextLinkSelector);
if (!newNextLink) {
sentinel.innerHTML = `${noMoreText}
`;
if (window.infiniteScrollObserver) window.infiniteScrollObserver.disconnect();
}
} catch (error) {
console.error('Infinite scroll error:', error);
sentinel.innerHTML = `加载失败,点击重试
`;
} finally {
isLoading = false;
}
};
window.infiniteScrollObserver = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
loadNextPage();
}
}, {
rootMargin: '200px'
});
window.infiniteScrollObserver.observe(sentinel);
};