You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

分页切换后电商分类选中状态丢失,如何持久化选择数据?

问题解决思路与方案

核心问题分析

  • 分页跳转是GET请求,未携带选中的分类ID,导致后端使用默认空列表查询,筛选状态丢失
  • 使用localStorage后出现的页面回退问题,是因为分页跳转触发页面刷新,前端先从localStorage恢复状态,但页面刷新后默认GET请求又覆盖了数据

分步解决方案

1. 让分页请求携带筛选参数(兼容页面刷新场景)

修改分页视图的URL生成逻辑,把当前选中的分类ID拼接到跳转链接中:

<!-- Pagination Buttons -->
<div class="d-flex justify-content-center">
    <ul class="pagination">
        @for (int i = 1; i <= Model.MetaData.pages; i++)
        {
            // 拼接分类参数
            var categoryParams = Model.CategoryIds?.Any() == true 
                ? Model.CategoryIds.Select(id => $"categoryIds={id}").Aggregate((a,b) => $"{a}&{b}")
                : "";
            var pageUrl = categoryParams != "" 
                ? $"{Url.Action("Index", new { page = i })}&{categoryParams}"
                : Url.Action("Index", new { page = i });
                
            <li class="page-item @(i == Model.MetaData.page ? "active" : "")">
                <a class="page-link" href="@pageUrl">@i</a>
            </li>
        }
    </ul>
</div>

同时简化Controller的Index方法,利用模型绑定自动接收分类参数:

[Authorize]
public async Task<IActionResult> Index(GetECommerceIndexQuery request)
{
    var result = await MediatrSend(request);
    return View(result);
}

2. 前端改用AJAX分页,避免页面刷新

修改前端脚本,将分页跳转改为异步请求,同时维护选中状态:

@section scripts {
    <script>
        let selectedCategoryIds = [];

        $(document).ready(function () {
            // 页面加载时恢复选中状态
            restoreSelectedCategories();
            
            // 分类复选框点击事件
            $(".checkbox-item").click(function () {
                selectedCategoryIds = $(".checkbox-item:checked").map(function () {
                    return parseInt(this.value, 10);
                }).get();
                localStorage.setItem("selectedCategoryIds", JSON.stringify(selectedCategoryIds));
                loadProducts(1); // 筛选后默认回到第一页
            });

            // 分页点击事件,阻止默认跳转
            $(".page-link").click(function (e) {
                e.preventDefault();
                const pageNum = parseInt($(this).text());
                loadProducts(pageNum);
            });
        });

        // 加载指定页的商品数据
        function loadProducts(page) {
            $.ajax({
                url: '@Url.Action("GetCategories", "ECommerce")',
                type: 'POST',
                data: JSON.stringify({
                    CategoryIds: selectedCategoryIds,
                    Page: page,
                    PageSize: 6
                }),
                contentType: 'application/json; charset=utf-8',
                success: function (data) {
                    renderProducts(data.ProductData);
                    updatePagination(data.MetaData);
                },
                error: function (error) {
                    console.error('加载失败:', error);
                }
            });
        }

        // 渲染商品列表(原逻辑保留)
        function renderProducts(products) {
            $('#productContainer').empty();

            $.each(products, function (index, product) {
                var productUrl = '@Url.Action("ProductDetail", new { id = 0 })'.replace("0", product.Id);

                var productHtml = `
                            <div class="col-md-4 col-lg-12 col-xxl-4">
                                <a href="${productUrl}" class="product-link">
                                    <div class="card card-custom gutter-b card-stretch">
                                        <div class="card-body d-flex flex-column rounded bg-light justify-content-between">
                                            <div class="text-center rounded mb-7">
                                                <img src="assets/media/products/${product.ProductName}" class="mw-100 w-200px" alt="${product.ProductName}">
                                            </div>
                                            <div>
                                                <h4 class="font-size-h5">
                                                    <span class="text-dark-75 font-weight-bolder">${product.ProductName}</span>
                                                </h4>
                                                <div class="font-size-h6 text-muted font-weight-bolder">${product.Price}</div>
                                            </div>
                                        </div>
                                    </div>
                                </a>
                            </div>`;

                $('#productContainer').append(productHtml);
            });
        }

        // 更新分页控件
        function updatePagination(metaData) {
            const paginationContainer = $('.pagination');
            paginationContainer.empty();

            for (let i = 1; i <= metaData.pages; i++) {
                const activeClass = i === metaData.page ? 'active' : '';
                paginationContainer.append(`
                    <li class="page-item ${activeClass}">
                        <a class="page-link" href="#">${i}</a>
                    </li>
                `);
            }

            // 重新绑定分页点击事件
            $(".page-link").off('click').click(function (e) {
                e.preventDefault();
                const pageNum = parseInt($(this).text());
                loadProducts(pageNum);
            });
        }

        // 恢复选中的分类状态(优先从URL参数获取,兼容直接访问链接)
        function restoreSelectedCategories() {
            const urlParams = new URLSearchParams(window.location.search);
            const categoryIdsFromUrl = urlParams.getAll('categoryIds').map(id => parseInt(id));
            
            if (categoryIdsFromUrl.length > 0) {
                selectedCategoryIds = categoryIdsFromUrl;
                categoryIdsFromUrl.forEach(id => {
                    $(`.checkbox-item[value="${id}"]`).prop('checked', true);
                });
            } else {
                const savedIds = localStorage.getItem("selectedCategoryIds");
                if (savedIds) {
                    selectedCategoryIds = JSON.parse(savedIds);
                    selectedCategoryIds.forEach(id => {
                        $(`.checkbox-item[value="${id}"]`).prop('checked', true);
                    });
                }
            }

            if (selectedCategoryIds.length > 0) {
                loadProducts(1);
            }
        }
    </script>
}

3. 调整后端接口支持分页参数

修改Controller的GetCategories方法,接收完整的查询参数:

[Authorize]
[HttpPost]
public async Task<IActionResult> GetCategories([FromBody] GetECommerceIndexQuery request)
{
    var result = await MediatrSend(request);
    return Json(result);
}

关键说明

  • 分页改用AJAX异步加载,彻底避免页面刷新导致的状态丢失
  • 同时支持URL参数和localStorage恢复选中状态,兼容直接访问带筛选条件的链接
  • 后端统一使用GetECommerceIndexQuery接收参数,保持逻辑一致性

内容的提问来源于stack exchange,提问作者Onur Serbes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 00:40:55