• ASP.NET MVC利用PagedList分页(二)PagedList+Ajax+JsRender


    原文

      昨天在ASP.NET MVC利用PagedList分页(一)的 最后一节提到,一个好的用户体验绝对不可能是点击下一页后刷新页面,所以今天来说说利用Ajax+PagedList实现无刷新(个人绝对局部刷新更准确 些)的分页。其实在PagedList.Mvc中早已经为我们提供好了Ajax分页的各种东东,但是这里我要自己写下。

      实现思想:

        1、客户端发送Ajax请求。2、服务器端响应请求并将响应结果回传给客户端。3、客户端接收响应结果并进行数据绑定。

      实现方案:

      大多数人都知道这个思想,但是面对一个陌生的环境,我不得不理一下思路然后再 讨论实现方案:1、利用Jquery Ajax发送分页请求。2、进行数据划分并利用SataticPagedList<T>(我个人比较喜欢这个,也可以用 ToPagedList)绑定。3、利用Jquery Ajax接收数据并进行数据绑定。ok,实现方案出炉,下面直接上代码:

    复制代码
    //View:Views/Person/Ajax
    <link href="/Content/PagedList.css" type="text/css" rel="Stylesheet" />
    ......
    <script type="text/javascript" src="/Scripts/jquery-1.5.1.js"></script>
    <script type="text/javascript">
        $(function () {
            getPersonByAjax(1);
        });
      //Ajax请求
        var getPersonByAjax = function (pageNumber) {
            $.ajax({
                url: "/Person/AjaxPage?page=" + pageNumber,
                type: "POST",
                dataType: "json",
                success: function (data) {
                    //接收数据(data)并绑定
                    var html = "";
                    $.each(data.persons, function (i, item) {
                        html += "<tr><td>" + item.FirstName + "</td><td>" + item.LastName +
                            "</td><td><a href='/Person/Edit/" + item.PersonID + "'>Edit</a> | <a href='/Person/Details/" +
                            item.PersonID + "'>Details</a> | <a href='/Person/Delete/" + item.PersonID + "'>Delete</a></td></tr>";
                    });
                    $("#personList").html(html);
                },
                error: function (result) {
                    alert(result.statusText);
                },
                complete: function (jqXHR) {
                    jqXHR = null;
                }
            });
        }
    </script>
    
    //Controller:PersonController
    
    //响应Ajax请求 public ActionResult AjaxPage(int? page) { int pageIndex = page ?? 1; int pageSize = 2; int totalCount = 0; var persons = GetPerson(pageIndex, pageSize, ref totalCount); var personsAsIPageList = new StaticPagedList<Person>(persons, pageIndex, pageSize, totalCount); return Json(new { persons = personsAsIPageList},JsonRequestBehavior.AllowGet); } public List<Person> GetPerson(int pageIndex, int pageSize, ref int totalCount) { var persons = (from p in db.Persons orderby p.PersonID descending select p).Skip((pageIndex - 1) * pageSize).Take(pageSize); totalCount = db.Persons.Count(); return persons.ToList(); }
    (注:这里运用到了Json在服务器和客户端之间传递的知识额...我非常喜欢Json接收强类型对象,后头有机会慢慢谈下。)
    复制代码

       在写“接收数据(data)并绑定之前”我还在天真的想,personAdIPagedList不会回吧HasPreviousPage、HasNextNextPage也传递过来呢?于是我用Fillder服务器端到底会传递什么回来,结果如下:

      挂了,貌似他至传回了persons的json数据,那分页咋办呢?原来在IPagedList<T>中有个GetMetaData,他会返回一个PagedListMetaData对象,在这里进行了分页导航相关属性的分装:

      添加分页导航

      good,这下我可以完善我的代码了。 如下:

    复制代码
    public ActionResult AjaxPage(int? page)
    {
        int pageIndex = page ?? 1;
        int pageSize = 2;
        int totalCount = 0;
        var persons = GetPerson(pageIndex, pageSize, ref totalCount);
        var personsAsIPageList = new StaticPagedList<Person>(persons, pageIndex, pageSize, totalCount);
         return Json(new { persons = personsAsIPageList, pager = personsAsIPageList.GetMetaData() }, JsonRequestBehavior.AllowGet);
    }
    复制代码

      可以看到这里PagedList传回了所有的分页信息。所以可以做分页导航了:

    复制代码
    //创建分页导航
                    var pager = data.pager;
                    html = "";
                    if (pager.HasPreviousPage) {
                        html += "<a href='#' onclick='getPersonByAjax(" + (pager.PageNumber - 1) + ");return false;'>&lt;&lt;</a> <a href='#' onclick='getPersonByAjax(1);return false;'>&lt; Prev</a>";
                    }
                    else {
                        html += "&lt;&lt; &lt; Prev";
                    }
                    html += " ";
                    if (pager.HasNextPage) {
                        html += "<a href='#' onclick='getPersonByAjax(" + (pager.PageNumber + 1) + ");return false;'>Next &gt;</a> <a href='#' onclick='getPersonByAjax(" + pager.PageCount + ");return false;'>&gt;&gt;</a>";
                    }
                    else {
                        html += "Next &gt; &gt;&gt;";
                    }
                    $("#pager").html(html);
    复制代码

       将上面代码插入success中,分页就创建好了。当我正在高兴的时候我大概忘记了刚刚做字符串拼接的辛苦。冷静下来后我和PagedList提供的实例(好像忘了给地址,给一个:https://github.com/TroyGoode/PagedList)进行了对比,对比结果是我无比蛋疼。在其提供实例中用到了jquery.tmpl.js,原来我们真的不用做如此多的字符处啊拼接工作。

      优化绑定

      jquery.tmpl.js是一个模板插件,能够用对象或数据等对模板(包含html、css等标签和绑定表达式。)进行渲染,举个例子:"<li class='XXX' id='liTemplate'>${name}</li>"这就是一个模板,包含html、css和绑定表达式(${name}),现在我们只需利用:$.template("templateName",$('#liTemplate').html());$.tmpl(templateName,list).appendTo('#liContainer');将模板渲染(tmpl)然后插入容器(liContainer)展示即可。第一句将liTemplate标记为一个模板,名称为templateName。第二句利用list将templateName进行渲染,然后插入到liContainer中。list可以使一个数据,也可以是一个对象,例如:var  list = {"name":"hello world","name":"heihei"}。总之,tmpl可以让我们不用在写字符串连接,它的可见性太差了,极其难维护。同时,利用tmpl需要三要素:模板,容器,数据。利用数据渲染模板,将结果插入容器中我们便可以轻松完成js中的数据绑定。

      事后,我在其官网(https://github.com/jquery/jquery-tmpl)上查阅了相关治疗,发现jquey.tmpl还停留在测试期,并且不再提供升级,被jquery放弃了。。。下一代jquery 模板由JsRender和JsViews承担,相关资料可以去官网上看(JsRender:https://github.com/BorisMoore/jsrender;JsViews:https://github.com/BorisMoore/jsviews)。JsRedner和tmpl差不多,但是据介绍说,JsRender的渲染速度比tmpl快很多很多,到底快多少我也不知道,而且给我的直观感受就是,JsRedner比tmpl的语法简单的写。。这个我喜欢。JsRender强调纯粹的基于字符串的渲染,而且可以不需要dom和jquery的支持,上面我们可以看到tmpl是需要的:$.template("templateName",$('#liTemplate').html());;而JsViews则是建立在JsRender上更高层次的封装,他强调建立交互式的数据驱动视图,具体的貌似我目前还不是很了解。

      ok,废话少说,关于JsRender相关的东东在后头我在慢慢整理出来,下面看看它在项目中间的运用,当时我真的大吃一惊,修改View:Views/Person/Ajax代码如下:

    复制代码
    //View:Views/Person/Ajax
    ......
    //绑定模板
    <script type="text/x-jsrender" id="personListTemplate">
        {{for persons}}
            <tr>
                <td>{{:FirstName}}</td>
                <td>{{:LastName}}</td>
                <td>
                    <a href="/Person/Edit/{{:PersonID}}">Edit</a> | 
                    <a href="/Person/Details/{{:PersonID}}">Details</a> | 
                    <a href="/Person/Delete/{{:PersonID}}">Delete</a>
                </td>
            </tr>
        {{/for}}
    </script>
    //分页模板
    <script type="text/x-jsrender" id="pagerTemplate">
        {{if HasPreviousPage}}
            <a href="#" onclick="getPersonByAjax(1);return false;">&lt;&lt;</a>
            <a href="#" onclick="getPersonByAjax({{:PageNumber - 1}});return false;">&lt; Prev</a>
        {{else}}
            &lt;&lt;&nbsp;&lt; Prev
        {{/if}}
        &nbsp;
        {{if HasNextPage}}
            <a href="#" onclick="getPersonByAjax({{:PageNumber + 1}});return false;">Next &gt;</a>
            <a href="#" onclick="getPersonByAjax({{:PageCount}});return false;">&gt;&gt;</a>
        {{else}}
            Next &gt;&nbsp;&gt;&gt;
        {{/if}}
    </script>
    
    ........
    
    <script type="text/javascript" src="/Scripts/jquery-1.5.1.min.js"></script>
    <script type="text/javascript" src="/Scripts/jsrender.js"></script>
    <script type="text/javascript">
        $(function () {
            getPersonByAjax(1);
        });
    
        var getPersonByAjax = function (pageNumber) {
            $.getJSON("/Person/AjaxJsRenderPage",
                { "page": pageNumber })
                .success(function (data) {
                    $("#personList").empty();
              //JsRender渲染、渲染结果(字符串)插入容器                
              $("#personList").append($("#personListTemplate").render(data)); $("#pager").html($("#pagerTemplate").render(data.pager)); }) .error(function (textStatus) { alert("msg:" + textStatus.statusText); }) .complete(function (jqXHQ) { jqXHQ = null; }); } </script>
    复制代码

       少去了太多的连接字符串代码(codeless),而且可见性很强,非常容易维护。ok,ajax分页就这么完成了。后头我们在慢慢谈下PagedList的分页思想和整理下JsRender相关的知识。 

      补充

      前面的代码在后来发现了两个问题:

        第一、分页时如何定位到具体页?

        第二、当数据为空时候的处理?

      第二个问题很简单,判断data.persons.length是否为0既可解决,第二个问题要用到window.location.hash。其实就是锚,不过我可以用“window.location.hash = XX”设置标签值和使用“window.location.hash”来获取标签值罢了。下面来看看如何使用location.hash进行分页和页码定位:

    复制代码
    $(function () {
            getPerson();
        });
    
        var getPerson = function () {
            var pageNumber;
            if (arguments[0] == null) {
                var hash = (window.location.hash);
                if (hash)
                    pageNumber = hash.slice(1);
                else {
                    pageNumber = 1;
                    window.location.hash = pageNumber;
                }
            }
            else {
                pageNumber = arguments[0];
                window.location.hash = pageNumber;
            }
            getPersonByAjax(pageNumber);
        }
    复制代码

       用上面代码替换$(function () {getPersonByAjax(1);});就ok了。可以看到,这里用window.location.hash来获取页面的页码和根据页码来设置window.location.hash,两只始终一致,这样就解决了ajax分页时的具体页定位问题。

  • 相关阅读:
    LYDSY模拟赛day3 序列
    LYDSY模拟赛day3 涂色游戏
    LYDSY模拟赛day3 平均数
    hdu1757 A Simple Math Problem
    清北国庆day1 (脑)残
    poj3070 Fibonacci
    uva10870 递推关系Recurrences
    湖南附中模拟day1 瞭望塔
    湖南附中模拟day1 收银员
    湖南附中模拟day1 金坷垃
  • 原文地址:https://www.cnblogs.com/jimcsharp/p/4785144.html
Copyright © 2020-2023  润新知