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

Blazor Contacts组件分页异常:SetPage方法接收错误页码值

Blazor分页组件点击页码始终触发最后一页的问题解决

问题现象

开发的Contacts Blazor组件分页功能异常:点击任意页码按钮(比如第2页),SetPage方法接收到的参数始终是最后一页的数值(如示例中的6),问题出在分页控件的for循环逻辑中。

原因分析

分页for循环里的@onclick="() => SetPage(i)"使用lambda表达式捕获了循环变量i的引用,而非每次迭代的具体数值。当循环执行完毕,所有按钮的点击事件都会使用i的最终值(即最后一页的页码),导致点击任意页码都跳转到最后一页。

解决方案

在for循环内部,将当前迭代的i值赋值给一个局部变量,让lambda捕获这个局部变量而非循环变量i。这样每个页码按钮的点击事件都会绑定当前迭代的正确页码值。

修正后的分页代码片段

<!-- Pagination Controls -->
<ul class="pagination mb-0">
    <li class="page-item @(CurrentPage == 1 ? "disabled" : "")">
        <button class="page-link" @onclick="() => SetPage(CurrentPage - 1)" disabled="@((CurrentPage == 1))">Previous</button>
    </li>
    @for (int i = 1; i <= TotalPages; i++)
    {
        // 创建局部变量存储当前页码
        var page = i;
        <li class="page-item @(CurrentPage == page ? "active" : "")">
            <button class="page-link" @onclick="() => SetPage(page)">@page</button>
        </li>
    }
    <li class="page-item @(CurrentPage == TotalPages ? "disabled" : "")">
        <button class="page-link" @onclick="() => SetPage(CurrentPage + 1)" disabled="@((CurrentPage == TotalPages))">Next</button>
    </li>
</ul>

完整修正后的组件代码

@page "/Contacts"
@rendermode InteractiveServer

<h3>Contacts Component</h3>

<!-- Search Bar -->
<div class="row mb-3">
    <div class="col-md-6">
        <input type="text" class="form-control" placeholder="Search contacts..." @bind="SearchTerm" @bind:event="oninput" />
    </div>
</div>

<!-- Table with Sorting -->
<table class="table table-striped">
    <thead>
        <tr>
            <th @onclick="() => SortByColumn(nameof(Contact))">Contact @GetSortIcon(nameof(Contact))</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var contact in PagedContacts)
        {
            <tr>
                <td>
                    <button class="btn btn-link" @onclick="() => SelectContact(contact)">@contact</button>
                </td>
            </tr>
        }
    </tbody>
</table>

<!-- Pagination -->
<nav class="d-flex justify-content-between align-items-center">
    <!-- Page Label -->
    <span>Page @CurrentPage of @TotalPages (@FilteredContacts.Count() total records)</span>

    <!-- Pagination Controls -->
    <ul class="pagination mb-0">
        <li class="page-item @(CurrentPage == 1 ? "disabled" : "")">
            <button class="page-link" @onclick="() => SetPage(CurrentPage - 1)" disabled="@((CurrentPage == 1))">Previous</button>
        </li>
        @for (int i = 1; i <= TotalPages; i++)
        {
            var page = i;
            <li class="page-item @(CurrentPage == page ? "active" : "")">
                <button class="page-link" @onclick="() => SetPage(page)">@page</button>
            </li>
        }
        <li class="page-item @(CurrentPage == TotalPages ? "disabled" : "")">
            <button class="page-link" @onclick="() => SetPage(CurrentPage + 1)" disabled="@((CurrentPage == TotalPages))">Next</button>
        </li>
    </ul>
</nav>


@code {
    [Parameter] public List<string> ContactsList { get; set; } = new();
    [Parameter] public EventCallback<(string ContactName, string FieldName)> OnContactSelected { get; set; }
    [Parameter] public string TargetField { get; set; } = string.Empty;

    private string _searchTerm = "";
    private string SortColumn = nameof(Contact);
    private bool SortAscending = true;
    private int CurrentPage = 1;
    private int PageSize = 5;

    // 修正搜索属性的递归引用问题
    private string SearchTerm
    {
        get => _searchTerm;
        set
        {
            if (_searchTerm != value)
            {
                _searchTerm = value;
                CurrentPage = 1; // 搜索时重置到第一页
            }
        }
    }

    private void SortByColumn(string column)
    {
        if (SortColumn == column)
        {
            SortAscending = !SortAscending;
        }
        else
        {
            SortColumn = column;
            SortAscending = true;
        }
    }


    private void SetPage(int page)
    {
        CurrentPage = page;
    }

    // 过滤、排序后的联系人列表
    private IEnumerable<string> FilteredContacts => ContactsList
        .Where(c => string.IsNullOrEmpty(SearchTerm) || c.Contains(SearchTerm, StringComparison.OrdinalIgnoreCase))
        .OrderBy(c => SortAscending ? c : null)
        .ThenByDescending(c => SortAscending ? null : c);

    // 分页后的联系人列表
    private IEnumerable<string> PagedContacts => FilteredContacts
       .Skip((CurrentPage - 1) * PageSize)
       .Take(PageSize);

    private int TotalPages => (int)Math.Ceiling(FilteredContacts.Count() / (double)PageSize);

    protected override void OnParametersSet()
    {
        Console.WriteLine($"CurrentPage: {CurrentPage}, TotalPages: {TotalPages}");
        Console.WriteLine($"FilteredContacts Count: {FilteredContacts.Count()}, PagedContacts Count: {PagedContacts.Count()}");
    }

    private async Task SelectContact(string contact)
    {
        if (OnContactSelected.HasDelegate)
        {
            await OnContactSelected.InvokeAsync((contact, TargetField));
        }
    }

    private string GetSortIcon(string column)
    {
        if (SortColumn == column)
        {
            return SortAscending ? "▲" : "▼";
        }
        return string.Empty;
    }

    public class Contact
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public string Phone { get; set; }
    }
}

补充说明

原代码中_searchTerm属性存在递归引用问题(get返回自身),会导致栈溢出,已在修正代码中修复为正确的属性定义,确保搜索时能正常重置页码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 19:38:10