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分頁時的具體頁定位問題。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM