如何通过XHR实现JSON分页数据无刷新渲染至HTML?
Got it, let's fix this pagination functionality step by step. First, let's clarify the core requirements: we need to fetch paginated JSON data via XHR, render both the content and pagination controls without page reloads, and handle prev/next buttons plus direct page jumps.
First, let's assume your sample JSON response looks like this (adjust if your structure is different):
{ "data": [ {"id": 1, "title": "Sample Item 1"}, {"id": 2, "title": "Sample Item 2"} ], "pagination": { "current_page": 1, "total_pages": 5, "total_items": 10, "per_page": 2 } }
Here's the complete implementation, building on your existing code:
Step 1: Update HTML Structure (if needed)
Make sure you have containers for content and pagination controls:
<div id="content-container"></div> <div class="pagination-controls"> <button id="prev-btn">上一页</button> <span id="page-status">第 1 页 / 共 5 页</span> <button id="next-btn">下一页</button> <div class="page-jump"> <input type="number" id="page-input" min="1" placeholder="输入页码"> <button id="jump-btn">跳转</button> </div> </div>
Step 2: Complete the JavaScript Logic
We'll add state tracking, data rendering, and event handlers:
// Track current pagination state let currentPage = 1; let totalPages = 1; // DOM Elements const contentContainer = document.getElementById('content-container'); const prevBtn = document.getElementById('prev-btn'); const nextBtn = document.getElementById('next-btn'); const pageStatus = document.getElementById('page-status'); const pageInput = document.getElementById('page-input'); const jumpBtn = document.getElementById('jump-btn'); // Fetch data and render everything function getData(page) { const xhr = new XMLHttpRequest(); // Replace with your actual API endpoint xhr.open('GET', `/your-api-endpoint?page=${page}`, true); xhr.onload = function() { if (xhr.status === 200) { const response = JSON.parse(xhr.responseText); const { data, pagination } = response; // Update state currentPage = pagination.current_page; totalPages = pagination.total_pages; // Render content list renderContent(data); // Update pagination controls updatePaginationControls(); } else { console.error('Failed to fetch data:', xhr.statusText); contentContainer.innerHTML = '<p>加载失败,请重试</p>'; } }; xhr.onerror = function() { console.error('Network error occurred'); contentContainer.innerHTML = '<p>网络错误,请检查连接</p>'; }; xhr.send(); } // Render the fetched data into the content container function renderContent(data) { if (data.length === 0) { contentContainer.innerHTML = '<p>当前页没有数据</p>'; return; } // Build HTML for items (adjust this to match your data structure) const itemsHtml = data.map(item => ` <div class="list-item"> <h3>${item.title}</h3> <p>ID: ${item.id}</p> </div> `).join(''); contentContainer.innerHTML = itemsHtml; } // Update pagination buttons and status text function updatePaginationControls() { // Update status text pageStatus.textContent = `第 ${currentPage} 页 / 共 ${totalPages} 页`; // Enable/disable prev button when on first page prevBtn.disabled = currentPage === 1; // Enable/disable next button when on last page nextBtn.disabled = currentPage === totalPages; // Update input's max attribute to prevent invalid entries pageInput.max = totalPages; } // Event handlers for pagination actions prevBtn.addEventListener('click', () => { if (currentPage > 1) { getData(currentPage - 1); } }); nextBtn.addEventListener('click', () => { if (currentPage < totalPages) { getData(currentPage + 1); } }); jumpBtn.addEventListener('click', () => { const targetPage = parseInt(pageInput.value); // Validate input to avoid invalid requests if (isNaN(targetPage) || targetPage < 1 || targetPage > totalPages) { alert(`请输入1-${totalPages}之间的页码`); return; } if (targetPage !== currentPage) { getData(targetPage); // Clear input after successful jump pageInput.value = ''; } }); // Optional: Allow pressing Enter key to trigger page jump pageInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { jumpBtn.click(); } }); // Initial load: fetch the first page on page load getData(1);
Key Explanations:
- State Tracking: We use
currentPageandtotalPagesvariables to keep track of the current pagination state, so we know exactly when to disable the prev/next buttons. - Separate Render Functions: Splitting
getData,renderContent, andupdatePaginationControlsmakes the code cleaner, easier to debug, and simpler to modify later. - Input Validation: We add checks to ensure users can't enter invalid page numbers, preventing unnecessary API requests and confusing error states.
- Error Handling: Basic error handling for network issues and failed requests ensures users get clear feedback instead of a broken page.
Just adjust the API endpoint in getData to match your actual backend, and modify the renderContent function to fit your specific data fields (e.g., replace title and id with your JSON's actual properties).
内容的提问来源于stack exchange,提问作者Ulvi

