zoukankan      html  css  js  c++  java
  • 无刷新分页

    无刷新,利用客户端的XMLHttpRequest对象发起请求到服务器,服务器响应后发回数据再由客户端进行接收,由于XMLHttpRequest对象发起的请求与响应是异步方式,而不是产生中断,因而其数据处理过程能在页面中呈现出无刷新的效果。
    进一步了解XMLHttpRequest对象,包括如下属性:
    onreadystatechange:每次状态改变所触发事件的事件处理程序。
    responseText:从服务器进程返回数据的字符串形式。
    responseXML:从服务器进程返回的DOM兼容的文档数据对象。
    status:从服务器返回的数字代码,比如常见的404(未找到)和200(已就绪)
    status Text:伴随状态码的字符串信息。
    readyState:状态值0、未初始化,对象已建立,但是尚未初始化(尚未调用open方法)
    1、初始化,对象已建立,尚未调用send方法
    2、发送数据,send方法已调用,但是当前的状态及http头未知
    3、数据传送中,已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误
    4、完成,数据接收完毕,此时可以通过通过responseXml和responseText获取完整的响应数据
    先看一个简单的URL请求:
    View Code
    //创建XMLHttpRequest,不同浏览器调用的创建方法不一样
    function XmlHttpRequest(){
    var requestObj = null;
    if(window.XMLHttpRequest){
    requestObj
    = new XMLHttpRequest();
    }
    else{
    try{
    requestObj
    = new ActiveXObject('MSXML2.XMLHTTP.4.0');
    }
    catch(e){
    try{
    requestObj
    = new ActiveXObject('MSXML2.XMLHTTP.3.0');
    }
    catch(e){
    try{
    requestObj
    = new ActiveXObject('MSXML2.XMLHTTP.2.6');
    }
    catch(e){
    try{
    requestObj
    = new ActiveXObject('MSXML2.XMLHTTP');
    }
    catch(e){
    try{
    requestObj
    = new ActiveXObject('Microsoft.XMLHTTP');
    }
    catch(e){}
    }
    }
    }
    }
    }

    if(requestObj == null){
    alert(
    'The browser does not surport XMLHTTP.');
    }

    return requestObj;
    }

    //发起POST请求并接收响应数据
    function GetData(){
    var xmlhttp = XmlHttpRequest();
    if(!xmlhttp){
    alert(
    '创建xmlhttp对象异常!');
    return;
    }

    var url = 'AjaxHandler/ProcPager.aspx';
    xmlhttp.open(
    'POST', url, false);
    xmlhttp.onreadystatechange
    = function(){
    if(xmlhttp.readyState == 4){
    document.getElementById(
    'divPager').innerHTML = '数据加载中,请稍候...';
    if(xmlhttp.status == 200){
    document.getElementById(
    'divPager').innerHTML = xmlhttp.responseText;
    }
    }
    }

    xmlhttp.send();
    }
     
    看看C#的分页,C#中用于分页的承载控件有很多,DataList、GridView、Repeater等。DataList、GridView天然支持分页,Repeater只能承载数据,没有分页功能,但利用PagedDataSource对象可让其实现分页功能。
    对于分页方式,可以通过Sql每次读取指定条数的记录,或者读取出所有记录,在内存中进行分页,下面是两种分页方式的实现: 
    View Code
    //分页存储过程
    CREATE PROCEDURE [dbo].[PROC_PAGER]
    @TABLE_NAME VARCHAR(
    2048), --表名或视图表
    @COLUMNS VARCHAR(
    1024), --欲选择字段列表
    @WHERE VARCHAR(
    2000), --查询条件
    @ORDER_BY VARCHAR(
    1000), --排序表达式
    @PAGE_INDEX INT,
    --页号,从1开始
    @PAGE_SIZE INT,
    --页尺寸
    @RECORD_COUNT INT OUTPUT
    AS
    BEGIN
    IF @COLUMNS IS NULL OR LTRIM(RTRIM(@COLUMNS))
    = ''
    BEGIN
    SET @COLUMNS
    = '*'
    END

    DECLARE @SQL_RECORD NVARCHAR(
    2000)
    SET @SQL_RECORD
    = 'SELECT @RECORD_COUNT = COUNT(0) FROM [' + @TABLE_NAME + '] WHERE 1 = 1 ' + @WHERE
    EXEC SP_EXECUTESQL @SQL_RECORD, N
    '@RECORD_COUNT INT OUTPUT', @RECORD_COUNT OUTPUT

    SET @ORDER_BY
    = ' ORDER BY ' + @ORDER_BY
    IF @PAGE_INDEX
    < 1
    BEGIN
    SET @PAGE_INDEX
    = 1
    END

    IF @PAGE_SIZE
    < 1
    BEGIN
    SET @PAGE_SIZE
    = 10
    END

    DECLARE @SQL_TEXT VARCHAR(MAX)
    SET @SQL_TEXT
    = 'SELECT ' + @COLUMNS +', ROWNUMBER
    FROM (
    SELECT
    ' + @COLUMNS + ', ROW_NUMBER() OVER(' + @ORDER_BY + ') AS ROWNUMBER
    FROM [
    ' + @TABLE_NAME + ']
    WHERE
    1 = 1 ' + @WHERE + '
    ) AS T
    WHERE ROWNUMBER BETWEEN
    ' + STR(((@PAGE_INDEX - 1)* @PAGE_SIZE+1)) + ' AND ' + STR(@PAGE_INDEX * @PAGE_SIZE)

    SET NOCOUNT ON
    EXECUTE(@SQL_TEXT)
    SET NOCOUNT OFF

    RETURN @@RowCount
    END

    /// <summary>
    /// DataTable分页
    /// </summary>
    public static DataTable DataTablePager(DataTable dt, int pageSize, int currentPage)
    {
    DataTable dtRet
    = dt.Clone();
    int records = dt.Rows.Count;
    int start = pageSize * (currentPage - 1);
    int end = pageSize * currentPage;
    if (end > records)
    {
    end
    = records;
    }

    DataRowCollection drc
    = dt.Rows;
    for (int i = start; i < end; i++)
    {
    dtRet.ImportRow(drc[i]);
    }

    return dtRet;
    }
     
    了解原理后,可以就分页功能进行实施,思路如下:
    1、Web页中定义分页数据的承载区域,用于显示分页输出。
    2、建立专用ASPX页,只输出分页内容及导航。
    3、建立JS分页对象,用于发起Ajax请求(请求地址为专用的分页ASPX页面),将获取到的内容加载到承载区域进行呈现。

    看看具体的实现,为Repeater实现分页功能,我们自己实现一个分页的自定义控件,主要功能就是根据总页数、当前页、每页大小计算出分页导航并输出,同时将PagedDataSource与页面中的Repeater进行绑定,再利用Ajax进行无刷新分页,原理简单,计算稍微麻烦,不多做解释,自己看代码: 
    View Code
    /// <summary>
    /// Repeater分页控件
    /// </summary>
    [ToolboxData("<{0}:FMPager runat=\"server\" />")]
    public class FMPager : WebControl, INamingContainer
    {
    protected static readonly string navigateClassFmt = "<div class=\"pageClass\">{0}</div>";
    protected static readonly string navigatePageTotalFmt = "<div class=\"pagetotal\">总记录:<strong>{0}</strong>&nbsp;&nbsp;&nbsp;页码:<span>{1}</span>/{2}</div>";
    protected static readonly string navigateAjaxlinkFmt = "<li><a href=\"javascript:;\" onclick=\"{0}('{1}');\" class=\"{3}\">{2}</a></li>";
    protected static readonly string navigateDisableLinkFmt = "<li><a href=\"#\">{0}</a></li>";
    protected static readonly string navigateGotoFmt = "<div class=\"fr\">转到第&nbsp;<input type=\"text\" style=\" 40px;\" value=\"{1}\" onblur=\"{0}(this.value);\">&nbsp;页</div>";
    private PagedDataSource pagedDataSource = null;

    public FMPager()
    {
    pagedDataSource
    = new PagedDataSource();
    }

    public override void DataBind()
    {
    base.DataBind();
    if (string.IsNullOrEmpty(repeaterId))
    {
    return;
    }

    Control repeater
    = FindRepeater(Page);
    if (repeater == null || !(repeater is Repeater))
    {
    return;
    }

    ChildControlsCreated
    = false;

    Repeater finalRepeater
    = repeater as Repeater;
    pagedDataSource.CurrentPageIndex
    = currentPageIndex;
    pagedDataSource.PageSize
    = pageSize;
    pagedDataSource.VirtualCount
    = recordCount;
    pagedDataSource.DataSource
    = DataSource;
    finalRepeater.DataSource
    = pagedDataSource;
    finalRepeater.DataBind();
    }

    /// <summary>
    /// 把数据内容传递到客户端
    /// </summary>
    protected override void Render(HtmlTextWriter output)
    {
    if (Site != null && Site.DesignMode)
    {
    CreateChildControls();
    }

    output.Write(OutputNavigate());
    base.Render(output);
    }

    /// <summary>
    /// 输出导航
    /// </summary>
    protected virtual string OutputNavigate()
    {
    //总页码数
    int pageCount = recordCount / pageSize;
    if (recordCount % pageSize != 0)
    {
    pageCount
    += 1;
    }

    if (currentPageIndex > pageCount)
    {
    currentPageIndex
    = pageCount;
    }

    StringBuilder sbNavigate
    = new StringBuilder();

    //输出跳转到
    sbNavigate.AppendFormat(navigateGotoFmt, pagerJs, currentPageIndex);

    //获取第一页、上一页
    sbNavigate.Append("<ul>");
    if (currentPageIndex > 1 && pageCount > 1)
    {
    sbNavigate.AppendFormat(navigateAjaxlinkFmt, pagerJs,
    1, "第一页", "");
    sbNavigate.AppendFormat(navigateAjaxlinkFmt, pagerJs, currentPageIndex
    - 1, "上一页", "");
    }
    else
    {
    sbNavigate.Append(
    string.Format(navigateDisableLinkFmt, "第一页"));
    sbNavigate.Append(
    string.Format(navigateDisableLinkFmt, "上一页"));
    }

    //获取数字页
    int navigateCount = 10; //每10页进行导航
    int navigateTotal = pageCount / navigateCount; //总计能生成多少个数字导航
    int pageInNavigate = ((currentPageIndex - 1) / navigateCount) + 1; //当前在第几个数字导航中

    //计算数字导航开始页序及结束页序
    int startIndex = (pageInNavigate - 1) * navigateCount + 1; //数字导航开始页序
    int endIndex = startIndex + navigateCount - 1; //数字导航结束页序
    if (endIndex > pageCount)
    {
    endIndex
    = pageCount;
    }

    string currentPageClass = "";
    for (int i = startIndex; i <= endIndex; i++)
    {
    currentPageClass
    = "";
    if (i == currentPageIndex)
    {
    currentPageClass
    = "pageactive";
    }

    sbNavigate.AppendFormat(navigateAjaxlinkFmt, pagerJs, i, i, currentPageClass);
    }

    //获取下一页、最后页
    if (currentPageIndex != pageCount && pageCount > 1)
    {
    sbNavigate.AppendFormat(navigateAjaxlinkFmt, pagerJs, currentPageIndex
    + 1, "下一页", "");
    sbNavigate.AppendFormat(navigateAjaxlinkFmt, pagerJs, pageCount,
    "最后页", "");
    }
    else
    {
    sbNavigate.AppendFormat(navigateDisableLinkFmt,
    "下一页");
    sbNavigate.AppendFormat(navigateDisableLinkFmt,
    "最后页");
    }

    sbNavigate.Append(
    "</ul>");

    //输出总页数、当前页
    sbNavigate.AppendFormat(navigatePageTotalFmt, recordCount, currentPageIndex, pageCount);

    return string.Format(navigateClassFmt, sbNavigate.ToString());
    }

    /// <summary>
    /// 查找输出Repeater
    /// </summary>
    private Control FindRepeater(Control ctrl)
    {
    Control retCtrl
    = ctrl.FindControl(repeaterId);
    if (retCtrl != null)
    {
    return retCtrl;
    }

    foreach (Control childCtrl in Page.Controls)
    {
    retCtrl
    = childCtrl.FindControl(repeaterId);
    if (retCtrl != null)
    {
    return retCtrl;
    }

    FindRepeater(retCtrl);
    }

    return null;
    }

    /// <summary>
    /// 绑定数据源
    /// </summary>
    public IEnumerable DataSource
    {
    get;
    set;
    }

    [Description(
    "当前页")]
    public int CurrentPageIndex
    {
    get
    {
    currentPageIndex
    = HTMLHelper.QueryStringInt("p");
    if (currentPageIndex <= 0)
    {
    currentPageIndex
    = 1;
    }

    return currentPageIndex;
    }
    set
    {
    currentPageIndex
    = value;
    }
    }
    private int currentPageIndex = 0;

    [Description(
    "分页控件ID")]
    public string RepeaterId
    {
    get
    {
    return repeaterId;
    }
    set
    {
    repeaterId
    = value;
    }
    }
    private string repeaterId = "";

    [Description(
    "每页显示记录数")]
    public int PageSize
    {
    get
    {
    return pageSize;
    }
    set
    {
    pageSize
    = value;
    }
    }
    private int pageSize = 20;

    [Description(
    "总记录数")]
    public int RecordCount
    {
    get
    {
    return recordCount;
    }
    set
    {
    recordCount
    = value;
    }
    }
    private int recordCount = 0;

    [Description(
    "JS分页函数")]
    public string PagerJs
    {
    get
    {
    return pagerJs;
    }
    set
    {
    pagerJs
    = value;
    }
    }
    private string pagerJs = "pagerObj.Page";
    }
     
    定义一个输出控件,继承自FMPager,用于输出具体的分页的内容:
    View Code
    /// <summary>
    /// 存储过程分页
    /// </summary>
    public class ProcPager : FMPager
    {
    protected override void OnLoad(EventArgs e)
    {
    base.OnLoad(e);
    FM.Business.ProcPager inf
    = new Business.ProcPager();
    int recordCount = 0;
    DataSet ds
    = inf.GetProcList("TEST", "ID, NAME, VAL", "", "ID", this.CurrentPageIndex, this.PageSize, ref recordCount);
    this.RecordCount = recordCount;
    this.DataSource = ds.Tables[0].DefaultView;
    base.DataBind();
    }
    }
     
    在专用ASPX页中调用,全部内容如下,没有HTML开始结束标识,只有输出内容:
    View Code
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ProcPager.aspx.cs" Inherits="AjaxHandler_ProcPager" %>
    <asp:Repeater ID="rpList" runat="server">
    <HeaderTemplate>
    <table class="tb1" cellspacing="2">
    <tr class="tr_bg">
    <td style=" 80%;">名称</td>
    <td></td>
    </tr>
    </HeaderTemplate>
    <ItemTemplate>
    <tr class="tr_bg2">
    <td><%# Eval("NAME") %></td>
    <td><%# Eval("VAL") %></td>
    </tr>
    </ItemTemplate>
    <FooterTemplate>
    </table>
    </FooterTemplate>
    </asp:Repeater>
    <ctrl:ProcPager ID="pagerTest" RepeaterId="rpList" PageSize="2" runat="server" />
     
    最后是JS分页函数:
    View Code
    /*
    JS分页对象
    参数:
    containerId:载体的容器ID
    url:分页数据地址
    callbackFn:分页数据加载完成后的回调函数
    */
    function PagerObj(containerId, url, callbackFn){
    var obj = new Object;
    obj.Page
    = page;

    function page(currentIndex){
    var finalUrl = url;
    if(finalUrl.indexOf('?') == -1){
    finalUrl
    += '?';
    }

    finalUrl
    += '&p=' + currentIndex;
    finalUrl
    += '&clearBuffer=' + RandomKey(); //消除浏览器缓存
    var xmlhttp = XmlHttpRequest();
    if(!xmlhttp){
    alert(
    '创建xmlhttp对象异常!');
    return;
    }

    xmlhttp.open(
    'POST', finalUrl, false);
    xmlhttp.onreadystatechange
    = function(){
    if(xmlhttp.readyState == 4){
    document.getElementById(containerId).innerHTML
    = '数据加载中,请稍候...';
    if(xmlhttp.status == 200){
    document.getElementById(containerId).innerHTML
    = xmlhttp.responseText;
    if(callbackFn != null){
    callbackFn();
    }
    }
    }
    }

    xmlhttp.send();
    }

    return obj;
    }

    Web页面的输出:
    View Code
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    <title></title>
    </head>
    <body>
    <form id="form1" runat="server">
    <div id="divPager" style="float: left; 100%;">分页数据的承载区域</div>
    </form>
    <script type="text/javascript">
    var pagerObj = null;

    window.onload
    = function(){
    LoadInfo();
    }

    function LoadInfo(){
    var url = 'AjaxHandler/ProcPager.aspx';
    pagerObj
    = new PagerObj('divPager', url, LoadInfoCallback);
    pagerObj.Page(
    1);
    }

    function LoadInfoCallback(){
    // alert('测试用回调函数');
    }

    //创建XMLHttpRequest,不同浏览器调用的创建方法不一样
    function XmlHttpRequest(){
    var requestObj = null;
    if(window.XMLHttpRequest){
    requestObj
    = new XMLHttpRequest();
    }
    else{
    try{
    requestObj
    = new ActiveXObject('MSXML2.XMLHTTP.4.0');
    }
    catch(e){
    try{
    requestObj
    = new ActiveXObject('MSXML2.XMLHTTP.3.0');
    }
    catch(e){
    try{
    requestObj
    = new ActiveXObject('MSXML2.XMLHTTP.2.6');
    }
    catch(e){
    try{
    requestObj
    = new ActiveXObject('MSXML2.XMLHTTP');
    }
    catch(e){
    try{
    requestObj
    = new ActiveXObject('Microsoft.XMLHTTP');
    }
    catch(e){}
    }
    }
    }
    }
    }

    if(requestObj == null){
    alert(
    'The browser does not surport XMLHTTP.');
    }

    return requestObj;
    }

    function PagerObj(containerId, url, callbackFn){
    var obj = new Object;
    obj.Page
    = page;

    function page(currentIndex){
    var finalUrl = url;
    if(finalUrl.indexOf('?') == -1){
    finalUrl
    += '?';
    }

    finalUrl
    += '&p=' + currentIndex;
    finalUrl
    += '&clearBuffer=' + RandomKey(); //消除浏览器缓存
    var xmlhttp = XmlHttpRequest();
    if(!xmlhttp){
    alert(
    '创建xmlhttp对象异常!');
    return;
    }

    xmlhttp.open(
    'POST', finalUrl, false);
    xmlhttp.onreadystatechange
    = function(){
    if(xmlhttp.readyState == 4){
    document.getElementById(containerId).innerHTML
    = '数据加载中,请稍候...';
    if(xmlhttp.status == 200){
    document.getElementById(containerId).innerHTML
    = xmlhttp.responseText;
    if(callbackFn != null){
    callbackFn();
    }
    }
    }
    }

    xmlhttp.send();
    }

    return obj;
    }

    //生成随机数,用于消除页面缓存
    function RandomKey(){
    var hex = new Array('0','1','2','3','4','5','6','7','8', '9','a','b','c','d','e','f');
    var t = '';
    for(var i = 0; i<32; i++){
    t
    += hex[Math.floor(Math.random() * 16)];
    }

    return t.toUpperCase();
    }
    </script>
    </body>
    </html>

    整个功能实施完毕,最后推荐使用jQuery,它封装了Ajax相关方法,我们不再需要自己实现XmlHttpRequest对象,只需利用jQuery进行异步请求即可,下面是利用jQuery实现的JS分页对象:
    function PagerObj(op){
    var obj = new Object;
    obj.Page
    = page;

    var settings = $.extend({
    containerId:
    'divPager', //容器编号
    url: '', //分页请求URL地址
    extendParams: '', //URL地址扩展参数
    callbackFn: null //加载完毕后的回调函数
    }, op);

    function page(currentIndex){
    var finalUrl = settings.url;
    if(finalUrl.indexOf('?') == -1){
    finalUrl
    += '?';
    }

    finalUrl
    += '&p=' + currentIndex;
    finalUrl
    += '&clearBuffer=' + RandomKey(); //消除浏览器缓存
    $.ajax({
    type:
    "POST",
    url: finalUrl,
    data: settings.extendParams,
    success:
    function(html){
    pageCallback(html);
    }
    });
    }

    function pageCallback(html){
    $(
    '#' + settings.containerId).html(html);
    if(settings.callbackFn != null){
    settings.callbackFn();
    }
    }

    return obj;
    }

    调用方法:
    function LoadInfo(){
    var url = 'AjaxHandler/ProcPager.aspx';
    pagerObj
    = new PagerObj({
    url: url,
    callbackFn: LoadInfoCallback
    });
    pagerObj.Page(
    1);
    }

    顺带一提,利用上面的JS分页对象可以实现同一页中的多个分页列表:
    View Code
    var pagerObj = null;
    var pagerTestObj = null;

    $(
    function(){
    LoadInfo();
    LoadTestInfo();
    })

    function LoadInfo(){
    var url = 'AjaxHandler/ProcPager.aspx';
    pagerObj
    = new PagerObj({
    url: url
    });
    pagerObj.Page(
    1);
    }

    function LoadTestInfo(){
    var url = 'AjaxHandler/TestPager.aspx';
    pagerTestObj
    = new PagerObj({
    containerId:
    'divTestPager',
    url: url
    });
    pagerTestObj.Page(
    1);
    }


    最终效果:


    放出本文源码:
    Pager_Demo.rar
  • 相关阅读:
    基于NIO的服务器模型
    Thinking in java 笔记三
    Thinking in java 笔记二
    Thinking in java 笔记一
    Windows 上的苹果 mac Time Machine 时间机器免费替代品 FreeFileSync 操作指南
    扫描仪扫描文件处理-ABBYY对扫描版PDF文字加黑加粗、去除背景漂白
    扫描仪扫描文件处理-Photoshop批处理无响应问题
    阅读-Calibre Library转PDF、EPUB配置
    扫描仪扫描文件处理-图像扫描加工到生成PDF步骤简述[JAVA版]
    扫描仪扫描文件处理-纸书切割扫描步骤
  • 原文地址:https://www.cnblogs.com/FlySoul/p/2079082.html
Copyright © 2011-2022 走看看