如何修复含分类与子分类筛选的分页异常问题?
问题分析与修复方案
核心问题排查
你的分页异常来自以下代码缺陷:
- 重复定义冲突:全局与
DOMContentLoaded回调里重复定义了同名函数(updateProductList、renderProducts)和变量,导致逻辑覆盖、状态混乱 - 分页计算错误:子分类逻辑里总页数用浮点值比较,分类逻辑里用
currentPage * 4判断分页,和每页20条的设定完全不符 - 重复绑定事件:每次调用更新函数都重新给复选框绑定
change事件,触发多次请求导致状态异常 - 数据显示覆盖:渲染函数最后把总产品数元素改成当前页数量,导致分页判断依赖的总数量丢失
修复后的完整代码
// 全局变量统一声明 const productList = document.querySelector("#products"); const productCountElement = document.querySelector("#product-count"); let currentPage = 1; const pageElement = document.querySelector("#page-number"); const prevPageButton = document.getElementById("prevPage"); const nextPageButton = document.getElementById("nextPage"); let totalProducts = 0; const PER_PAGE = 20; // 统一每页数量常量 // 统一产品渲染函数 function renderProducts(products) { productList.innerHTML = ""; let currentRow; let counter = 0; pageElement.innerHTML = `Page ${currentPage}`; products.forEach((product) => { if (counter % 4 === 0) { currentRow = productList.insertRow(); } const cell = currentRow.insertCell(); cell.style.width = "200px"; cell.style.marginRight = "10px"; const productInfo = document.createElement("div"); productInfo.classList.add("product-info"); const idHeading = document.createElement("h3"); idHeading.textContent = product.id; productInfo.appendChild(idHeading); const fabricHeading = document.createElement("h6"); fabricHeading.textContent = product.fabric; productInfo.appendChild(fabricHeading); const designNoHeading = document.createElement("h4"); designNoHeading.textContent = product.design_no; productInfo.appendChild(designNoHeading); cell.appendChild(productInfo); counter++; if (counter === 4) { currentRow = productList.insertRow(); counter = 0; } }); // 显示当前页数量/总数量 productCountElement.textContent = `${products.length} / ${totalProducts}`; } // 子分类筛选逻辑 function updateSubcategoryProducts() { const selectedSubcategoryIds = Array.from( document.querySelectorAll(".subcategory-checkbox:checked") ).map(checkbox => checkbox.getAttribute("data-subcategory-id")); const url = selectedSubcategoryIds.length > 0 ? `get_products.php?subcategory_ids=${selectedSubcategoryIds.join(",")}&page=${currentPage}` : `get_products.php?page=${currentPage}`; fetch(url) .then(response => response.json()) .then(data => { totalProducts = data.total_count; renderProducts(data.products); updatePaginationState(); }); } // 分类筛选逻辑 function updateCategoryProducts() { const selectedCategoryIds = Array.from( document.querySelectorAll(".category-checkbox:checked") ).map(checkbox => checkbox.getAttribute("data-category-id")); const url = selectedCategoryIds.length > 0 ? `get_product_category.php?category_ids=${selectedCategoryIds.join(",")}&page=${currentPage}` : `get_product_category.php?page=${currentPage}`; fetch(url) .then(response => response.json()) .then(data => { totalProducts = data.total_count; renderProducts(data.products); updatePaginationState(); }); } // 统一分页状态更新 function updatePaginationState() { const totalPages = Math.ceil(totalProducts / PER_PAGE); nextPageButton.disabled = currentPage >= totalPages; prevPageButton.disabled = currentPage <= 1; } // 分页按钮事件 prevPageButton.addEventListener("click", () => { if (currentPage > 1) { currentPage--; // 判断当前激活的筛选类型 const hasCategory = document.querySelector(".category-checkbox:checked"); const hasSubcategory = document.querySelector(".subcategory-checkbox:checked"); hasCategory ? updateCategoryProducts() : updateSubcategoryProducts(); } }); nextPageButton.addEventListener("click", () => { const totalPages = Math.ceil(totalProducts / PER_PAGE); if (currentPage < totalPages) { currentPage++; const hasCategory = document.querySelector(".category-checkbox:checked"); const hasSubcategory = document.querySelector(".subcategory-checkbox:checked"); hasCategory ? updateCategoryProducts() : updateSubcategoryProducts(); } }); // 初始化事件绑定(仅绑定一次) document.querySelectorAll(".subcategory-checkbox").forEach(checkbox => { checkbox.addEventListener("change", () => { currentPage = 1; // 筛选变更时重置到第一页 updateSubcategoryProducts(); }); }); document.querySelectorAll(".category-checkbox").forEach(checkbox => { checkbox.addEventListener("change", () => { currentPage = 1; // 筛选变更时重置到第一页 updateCategoryProducts(); }); }); // 页面加载初始化 document.addEventListener("DOMContentLoaded", updateSubcategoryProducts);
PHP端配套检查
确保你的两个接口做以下处理:
- 接收
page参数,计算offset = (page - 1) * 20,用LIMIT offset, 20获取对应页数据 - 同时返回筛选后的总产品数(执行不带LIMIT的COUNT查询),保证
data.total_count数值正确 - 处理空筛选参数的情况,返回全部产品
内容的提问来源于stack exchange,提问作者Ans Riaz
相关产品推荐
相关产品推荐

