首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

jQuery Pagination + JSON 無刷新分頁完整實作

     編輯:ASP.NET 基礎

前言

傳統 ASP.NET WebForms 分頁導致整頁回傳,體驗不佳。結合 jQuery Pagination Plugin 與 JSON 資料交換,可實現流暢的無刷新分頁。本文提供前後端完整程式碼,包含分頁控件初始化、AJAX 請求、JSON 序列化、資料表動態渲染。

一、前端頁面 (ASPX)

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SqlPage.aspx.cs" Inherits="SqlPage" %>
<!DOCTYPE html>
<html>
<head>
    <title>無刷新分頁示範</title>
    <link href="css/pagination.css" rel="stylesheet" />
    <style>
        #tblData { width: 100%; border-collapse: collapse; }
        #tblData th, #tblData td { border: 1px solid #ddd; padding: 8px; text-align: center; }
        #tblData th { background: #f5f5f5; }
        .pagination { text-align: center; margin: 20px 0; }
        .pagination a, .pagination span { display: inline-block; padding: 6px 12px; margin: 0 2px; border: 1px solid #ddd; color: #007bff; text-decoration: none; }
        .pagination .current { background: #007bff; color: #fff; border-color: #007bff; }
        .pagination .disabled { color: #999; pointer-events: none; }
    </style>
</head>
<body>
    <form id="form1" runat="server">
        <table id="tblData">
            <thead>
                <tr><th>NewsID</th><th>Title</th><th>Category</th><th>Author</th><th>UpdateTime</th></tr>
            </thead>
            <tbody><!-- 資料由 JS 動態填充 --></tbody>
        </table>
        <div id="Pagination" class="pagination"></div>
    </form>

    <script src="js/jquery-1.12.4.min.js"></script>
    <script src="js/jquery.pagination.js"></script>
    <script>
        var pageSize = 20;
        
        $(function() {
            // 初始化分頁控件 (總筆數由後端輸出 <%=pageCount%>)
            $("#Pagination").pagination(<%=pageCount %>, {
                callback: PageCallback,
                prev_text: '上一頁',
                next_text: '下一頁',
                items_per_page: pageSize,
                num_display_entries: 5,
                current_page: 0,
                num_edge_entries: 1,
                link_to: 'javascript:void(0)' // 防止跳轉
            });
        });

        function PageCallback(pageIndex, jq) {
            LoadPageData(pageIndex + 1); // 插件從 0 起算,後端從 1 起算
        }

        function LoadPageData(pageIndex) {
            $.ajax({
                type: "POST",
                dataType: "json", // 直接解析 JSON
                url: 'SqlPage.aspx',
                data: { pageIndex: pageIndex, pageSize: pageSize },
                beforeSend: function() {
                    $("#tblData tbody").html('載入中...');
                },
                success: function(data) {
                    if (data && data.News && data.News.length > 0) {
                        RenderTable(data.News);
                    } else {
                        $("#tblData tbody").html('無資料');
                    }
                },
                error: function(xhr, status, error) {
                    $("#tblData tbody").html('載入失敗:' + error + '');
                }
            });
        }

        function RenderTable(newsList) {
            var html = [];
            $.each(newsList, function(i, news) {
                html.push('');
                html.push('' + news.NewsID + '');
                html.push('' + htmlEncode(news.Title) + '');
                html.push('' + htmlEncode(news.SmallClassName) + '');
                html.push('' + htmlEncode(news.Author) + '');
                html.push('' + news.Updatetime + '');
                html.push('');
            });
            $("#tblData tbody").html(html.join(''));
        }

        // 簡易 HTML 編碼防 XSS
        function htmlEncode(str) {
            return $('
').text(str).html(); } </script> </body> </html>

二、後端程式碼 (CodeBehind)

using System;
using System.Data;
using System.Web.UI;

public partial class SqlPage : Page
{
    public int pageCount = 0; // 供前端 <%=pageCount%> 使用
    private const string ConnString = "server=192.168.1.91;database=ReportDB;uid=sa;pwd=123456";

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            // 首次載入:只計算總筆數,渲染分頁控件
            pageCount = GetTotalCount();
        }
        else
        {
            // AJAX 回傳:檢查分頁參數
            if (Request["pageIndex"] != null && Request["pageSize"] != null)
            {
                int pageSize = Convert.ToInt32(Request["pageSize"]);
                int pageIndex = Convert.ToInt32(Request["pageIndex"]);
                
                string json = GetPageDataJson(pageSize, pageIndex);
                Response.Clear();
                Response.ContentType = "application/json; charset=utf-8";
                Response.Write(json);
                Response.End(); // 關鍵:避免輸出頁面 HTML
            }
        }
    }

    private int GetTotalCount()
    {
        using (var conn = new System.Data.SqlClient.SqlConnection(ConnString))
        using (var cmd = new System.Data.SqlClient.SqlCommand("SELECT COUNT(*) FROM News", conn))
        {
            conn.Open();
            return Convert.ToInt32(cmd.ExecuteScalar());
        }
    }

    private string GetPageDataJson(int pageSize, int pageIndex)
    {
        // SQL Server 2012+ OFFSET/FETCH 分頁 (效能最佳)
        string sql = @"
            SELECT NewsID, Title, SmallClassName, Author, Updatetime
            FROM News
            ORDER BY NewsID DESC
            OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY";

        using (var conn = new System.Data.SqlClient.SqlConnection(ConnString))
        using (var cmd = new System.Data.SqlClient.SqlCommand(sql, conn))
        {
            cmd.Parameters.AddWithValue("@Offset", (pageIndex - 1) * pageSize);
            cmd.Parameters.AddWithValue("@PageSize", pageSize);
            
            conn.Open();
            using (var reader = cmd.ExecuteReader())
            {
                return ConvertJson.ToJson(reader, "News"); // 使用前文 ConvertJson 工具類
            }
        }
    }
}

三、ConvertJson.ToJson(DbDataReader) 關鍵實作

// 參考文章 54639 的 ConvertJson 類別
public static string ToJson(DbDataReader reader, string jsonName)
{
    var sb = new StringBuilder();
    sb.Append("{\"" + jsonName + "\":[");
    
    bool first = true;
    while (reader.Read())
    {
        if (!first) sb.Append(",");
        sb.Append("{");
        for (int i = 0; i < reader.FieldCount; i++)
        {
            string name = reader.GetName(i);
            Type type = reader.GetFieldType(i);
            object val = reader[i];
            sb.Append("\"" + name + "\":" + FormatValue(val, type));
            if (i < reader.FieldCount - 1) sb.Append(",");
        }
        sb.Append("}");
        first = false;
    }
    reader.Close();
    sb.Append("]}");
    return sb.ToString();
}

四、SQL 分頁寫法對比

SQL Server 版本分頁語法效能
2000/2005NOT IN / ROW_NUMBER() 子查詢較差,大數據深分頁慢
2008/2008 R2ROW_NUMBER() OVER() + CTE中等
2012+OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY最佳,原生支援
MySQL/PostgreSQLLIMIT @PageSize OFFSET @Offset最佳

五、進階優化建議

  • 快取總筆數:`pageCount` 可快取 30-60 秒,避免每次請求執行 `COUNT(*)`。
  • 參數化查詢:防 SQL 注入,促進查詢計畫重用。
  • 索引優化:`ORDER BY` 欄位 (NewsID) 必須有索引。
  • 前端防抖:若使用輸入框跳轉頁碼,加入 debounce 避免頻繁請求。
  • 錯誤處理:AJAX `error` 回呼顯示友善提示,記錄後端例外日誌。

六、現代化替代:ASP.NET Core + Fetch API

// Controller
[HttpGet]
public async Task List(int page = 1, int pageSize = 20)
{
    var query = _context.News.OrderByDescending(n => n.NewsID);
    var total = await query.CountAsync();
    var items = await query.Skip((page-1)*pageSize).Take(pageSize).ToListAsync();
    return Json(new { total, items, page, pageSize });
}

// 前端 (原生 Fetch)
async function loadPage(page) {
    const res = await fetch(`/News/List?page=${page}&pageSize=20`);
    const data = await res.json();
    renderTable(data.items);
    renderPager(data.total, data.pageSize, data.page);
}

總結

jQuery Pagination + JSON 無刷新分頁的核心架構:前端分頁控件管理 UI 狀態 → AJAX 請求帶分頁參數 → 後端參數化查詢當頁資料 → JSON 序列化回傳 → 前端動態渲染表格。關鍵點:`Response.End()` 截斷頁面輸出、參數化 SQL 防注入、OFFSET/FETCH 高效分頁、JSON 日期格式標準化。新專案建議採用原生 Fetch + ASP.NET Core Web API 架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved