2014年11月26日 星期三

基於 PagedList.Mvc 的基礎,作一個自己的分頁 ( Pager )

PagedList 與 PagedList.Mvc 已經用相當多篇的文章來做說明,這次來點不一樣的,就如同文章標題所說的,我們還是繼續使用 PagedList 與 PagedList.Mvc,但是卻不會去使用 PagedList.Mvc 所提供的 Pager,而是另外去建立我們自己的 Pager。

會這樣做的原因是為了想要讓分頁可以符合設計師或是前端設計師所做的分頁列樣式,因為 PagedList.Mvc 在使用上是可以符合大部分的情況,但是在一些比較特殊的使用情境下就無法滿足需求,所以作一個自己的 Pager 在就有其必要了。

 


其實我自己以及周遭的朋友也大部分都是使用 PagedList.Mvc 來實作分頁,但是卻會在其他人的專案裡看到的分頁實作卻是從頭到尾自己做,所謂的從頭到尾就是指基本的分頁處理核心與分頁顯示的 Html Helper 都是自己打造,我必須說我相當佩服這些開發者,因為分頁功能看起來好像沒有什麼功能與特別複雜的處理,但實際做過之後就會知道需要細心處理的細節是相當多的,而且常常這個專案所做的分頁功能到了另外一個專案是無法再重複使用,因為情境與需求不同,所以又得需要曾投到位在重新做一個分頁功能,這真的蠻累的。

我是一個相當懶的人,既然已經有人做好一個相當好用的功能時,除非必要,不然我不會選擇從頭到尾自己做(除非是真的想要練功或是想瞭解原理之外),所以 PagedList.Mvc 這樣一個好用的分頁功能,我就想要一直用下去,而不會想要自己去做一個新的出來。但是需求常常在變,PagedList.Mvc 也是會有無法滿足需求的時候,這個時候我所想的是如何在自己所做的 Pager 裡繼續使用 PagedList.Mvc 的既有基礎。

如果大家有興趣瞭解 PagedList 與 PagedList.Mvc 的原始碼的話,可以前往 PagedList 的 Github Repository 去下載原始碼或是直接在上面查看。

https://github.com/troygoode/PagedList

image

 

下圖所顯示的是一般使用 PagedList.Mvc 所完成的分頁功能,

image

 

但如果現在分頁的顯示是不一樣的,例如下圖的分頁樣式,

http://designshack.net/articles/css/building-a-custom-css3-pagination-user-interface/

image

其實我們可以使用 PagedList.Mvc 的 PagedListRenderOptions 類別去建立 instance,然後去設定類別裡的屬性,以做出符合需求的分頁樣式出來,不過這裡我是選擇建立新的 Pager 與相關類別。

 

實作

這邊我分別建立了 CustomPager.cs 與 PagingOptions.cs(專案還是需要透過 NuGet 安裝 PagedList 與 PagedList.Mvc),

image

PagingOptions.cs

using System.Collections.Generic;
using System.Linq;
 
namespace WebApplication1.Infrastructure.Paging
{
    public class PagingOptions
    {
        public IEnumerable<string> ContainerDivClasses { get; set; }
 
        public IEnumerable<string> UlElementClasses { get; set; }
 
        public IEnumerable<string> LiElementClasses { get; set; }
 
        public string CurrentPageElementClass { get; set; }
 
        public string NormalPageElementClass { get; set; }
 
        public string TextElementClass { get; set; }
 
        public string PageParameterName { get; set; }
 
        public bool Display { get; set; }
 
        public bool DisplayLinkToFirstPage { get; set; }
 
        public bool DisplayLinkToLastPage { get; set; }
 
        public bool DisplayLinkToPreviousPage { get; set; }
 
        public bool DisplayLinkToNextPage { get; set; }
 
        public bool DisplayLinkToIndividualPages { get; set; }
 
        public bool DisplayPageCountAndCurrentLocation { get; set; }
 
        public bool DisplayTotalItemCount { get; set; }
 
        public int? MaximumPageNumbersToDisplay { get; set; }
 
        public string LinkToFirstPageFormat { get; set; }
 
        public string LinkToPreviousPageFormat { get; set; }
 
        public string LinkToIndividualPageFormat { get; set; }
 
        public string LinkToNextPageFormat { get; set; }
 
        public string LinkToLastPageFormat { get; set; }
 
        public string PageCountAndCurrentLocationFormat { get; set; }
 
        public string TotalItemsFormat { get; set; }
 
 
        public PagingOptions()
        {
            ContainerDivClasses = new[] { "pagination-container" };
            UlElementClasses = new[] { "pagination" };
            LiElementClasses = Enumerable.Empty<string>();
            CurrentPageElementClass = "active";
 
            PageParameterName = "page";
 
            Display = true;
            DisplayLinkToFirstPage = true;
            DisplayLinkToPreviousPage = true;
            DisplayLinkToIndividualPages = true;
            DisplayLinkToNextPage = true;
            DisplayLinkToLastPage = true;
            DisplayPageCountAndCurrentLocation = true;
            DisplayTotalItemCount = true;
 
            MaximumPageNumbersToDisplay = 10;
            
            LinkToFirstPageFormat = "First";
            LinkToPreviousPageFormat = "Prev";
            LinkToIndividualPageFormat = "{0}";
            LinkToNextPageFormat = "Next";
            LinkToLastPageFormat = "Last";
            PageCountAndCurrentLocationFormat = "Page {0} of {1}.";
            TotalItemsFormat = "Total {0} items.";
        }
    }
}

CustomPager.cs

這個其實就是產生 Pager 的 Html Helper,我想裡面的程式就不逐一說明,程式碼並不會太艱深所以大家都可以很容易的瞭解內容,另外在 Pager 的程式裡是沒有使用到 Html Tag,因為有太多人都習慣把要顯示在網頁上的內容使用「組字串」的方式來達成,其實可以改用 TagBuilder,在有些地方會比較有彈性。

using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using PagedList;
 
namespace WebApplication1.Infrastructure.Paging
{
    public static class CustomPager
    {
        /// <summary>
        /// Pagers the specified HTML.
        /// </summary>
        /// <param name="html">The HTML.</param>
        /// <param name="list">The list.</param>
        /// <returns></returns>
        public static MvcHtmlString Pager(this HtmlHelper html, IPagedList list)
        {
            var options = new PagingOptions();
            return Pager(html, list, options);
        }
 
        /// <summary>
        /// 分頁 Pager 顯示
        /// </summary>
        /// <param name="html">The HTML.</param>
        /// <param name="list">The list.</param>
        /// <param name="options">The options.</param>
        /// <returns></returns>
        public static MvcHtmlString Pager(this HtmlHelper html,
            IPagedList list,
            PagingOptions options)
        {
            var queryString = html.ViewContext.HttpContext.Request.QueryString;
 
            //calculate start and end of range of page numbers
            var firstPageToDisplay = 1;
            var lastPageToDisplay = list.PageCount;
            var pageNumbersToDisplay = lastPageToDisplay;
 
            if (options.MaximumPageNumbersToDisplay.HasValue
                &&
                list.PageCount > options.MaximumPageNumbersToDisplay)
            {
                var maxPageNumbersToDisplay = options.MaximumPageNumbersToDisplay.Value;
 
                firstPageToDisplay = list.PageNumber - maxPageNumbersToDisplay / 2;
                if (firstPageToDisplay < 1)
                {
                    firstPageToDisplay = 1;
                }
 
                pageNumbersToDisplay = maxPageNumbersToDisplay;
                lastPageToDisplay = firstPageToDisplay + pageNumbersToDisplay - 1;
                if (lastPageToDisplay > list.PageCount)
                {
                    firstPageToDisplay = list.PageCount - maxPageNumbersToDisplay + 1;
                }
            }
 
            //從 ViewContext.RouteData.Values 取得目前的 RouteValueDictionary
            var routeValues =
                new RouteValueDictionary(html.ViewContext.RouteData.Values);
 
            var currentPage = list.PageNumber;
 
            var renderPager = new StringBuilder();
 
            if (!string.IsNullOrEmpty(queryString[options.PageParameterName]))
            {
                //與相應的 QueryString 綁定
                foreach (string key in queryString.Keys)
                {
                    if (queryString[key] != null && !string.IsNullOrEmpty(key))
                    {
                        routeValues[key] = queryString[key];
                    }
                }
                int.TryParse(queryString[options.PageParameterName], out currentPage);
            }
            else if (routeValues.ContainsKey(options.PageParameterName))
            {
                int.TryParse(routeValues[options.PageParameterName].ToString(), out currentPage);
            }
 
            //保留查詢字元到下一頁
            foreach (string key in queryString.Keys)
            {
                routeValues[key] = queryString[key];
            }
 
            if (currentPage <= 0)
            {
                currentPage = 1;
            }
 
            //first
            renderPager.Append(FirstPage(html, options, firstPageToDisplay, routeValues));
 
            //previous
            renderPager.Append(PreviousPage(html, options, currentPage, routeValues));
 
            //page
            renderPager.Append(IndividualPages(html, options, firstPageToDisplay, pageNumbersToDisplay, currentPage, routeValues));
 
            //next
            renderPager.Append(NextPage(html, options, currentPage, list.PageCount, routeValues));
 
            //last
            renderPager.Append(LastPage(html, options, lastPageToDisplay, list.PageCount, routeValues));
 
            //PageCountAndCurrentLocation
            renderPager.Append(PageCountAndCurrentLocation(options, currentPage, list.PageCount));
 
            //TotalItemCount
            renderPager.Append(TotalItemCount(list, options));
 
            var ul = new TagBuilder("ul") { InnerHtml = renderPager.ToString() };
            foreach (var item in options.UlElementClasses)
            {
                ul.AddCssClass(item);
            }
 
            var outerDiv = new TagBuilder("div") { InnerHtml = ul.ToString() };
            foreach (var item in options.ContainerDivClasses)
            {
                outerDiv.AddCssClass(item);
            }
 
            return new MvcHtmlString(outerDiv.ToString());
        }
 
 
 
        /// <summary>
        /// Firsts the page.
        /// </summary>
        /// <param name="html">The HTML.</param>
        /// <param name="options">The options.</param>
        /// <param name="firstPageToDisplay">The first page to display.</param>
        /// <param name="routeValues">The route values.</param>
        /// <returns></returns>
        private static string FirstPage(HtmlHelper html,
            PagingOptions options,
            int firstPageToDisplay,
            RouteValueDictionary routeValues)
        {
            var page = new StringBuilder();
 
            if (options.DisplayLinkToFirstPage)
            {
                if (firstPageToDisplay > 1)
                {
                    routeValues[options.PageParameterName] = 1;
                    var li = new TagBuilder("li")
                    {
                        InnerHtml = html.RouteLink(options.LinkToFirstPageFormat, routeValues).ToString()
                    };
                    page.Append(li);
                }
                else
                {
                    var li = new TagBuilder("li");
                    var first = new TagBuilder("a") { InnerHtml = options.LinkToFirstPageFormat };
                    first.Attributes.Remove("href");
                    first.Attributes.Add("style", "cursor: pointer;");
                    li.InnerHtml = first.ToString();
                    page.Append(li);
                }
            }
 
            return page.ToString();
        }
 
        /// <summary>
        /// Previouses the page.
        /// </summary>
        /// <param name="html">The HTML.</param>
        /// <param name="options">The options.</param>
        /// <param name="currentPage">The current page.</param>
        /// <param name="routeValues">The route values.</param>
        /// <returns></returns>
        private static string PreviousPage(HtmlHelper html,
            PagingOptions options,
            int currentPage,
            RouteValueDictionary routeValues)
        {
            var page = new StringBuilder();
 
            if (options.DisplayLinkToPreviousPage)
            {
                if (currentPage != 1 && currentPage > 1)
                {
                    routeValues[options.PageParameterName] = currentPage - 1;
                    var li = new TagBuilder("li")
                    {
                        InnerHtml = html.RouteLink(options.LinkToPreviousPageFormat, routeValues).ToString()
                    };
                    page.Append(li);
                }
                else
                {
                    var li = new TagBuilder("li");
                    var prev = new TagBuilder("a") { InnerHtml = options.LinkToPreviousPageFormat };
                    prev.Attributes.Remove("href");
                    prev.Attributes.Add("style", "cursor: pointer;");
                    li.InnerHtml = prev.ToString();
                    page.Append(li);
                }
            }
            return page.ToString();
        }
 
        /// <summary>
        /// Individuals the pages.
        /// </summary>
        /// <param name="html">The HTML.</param>
        /// <param name="options">The options.</param>
        /// <param name="firstPageToDisplay">The first page to display.</param>
        /// <param name="pageNumbersToDisplay">The page numbers to display.</param>
        /// <param name="currentPage">The current page.</param>
        /// <param name="routeValues">The route values.</param>
        /// <returns></returns>
        private static string IndividualPages(HtmlHelper html,
            PagingOptions options,
            int firstPageToDisplay,
            int pageNumbersToDisplay,
            int currentPage,
            RouteValueDictionary routeValues)
        {
            var page = new StringBuilder();
 
            if (!options.DisplayLinkToIndividualPages)
            {
                return page.ToString();
            }
 
            foreach (var i in Enumerable.Range(firstPageToDisplay, pageNumbersToDisplay))
            {
                var li = new TagBuilder("li");
 
                if (i == currentPage)
                {
                    if (!string.IsNullOrWhiteSpace(options.CurrentPageElementClass))
                    {
                        li.AddCssClass(options.CurrentPageElementClass);
                    }
                    li.SetInnerText(i.ToString());
                }
                else
                {
                    routeValues[options.PageParameterName] = i;
                    if (!string.IsNullOrWhiteSpace(options.NormalPageElementClass))
                    {
                        li.AddCssClass(options.NormalPageElementClass);
                    }
                    li.InnerHtml = html.RouteLink(i.ToString(), routeValues).ToString();
                }
 
                page.Append(li);
            }
 
            return page.ToString();
        }
 
        /// <summary>
        /// Nexts the page.
        /// </summary>
        /// <param name="html">The HTML.</param>
        /// <param name="options">The options.</param>
        /// <param name="currentPage">The current page.</param>
        /// <param name="pageCount">The page count.</param>
        /// <param name="routeValues">The route values.</param>
        /// <returns></returns>
        private static string NextPage(HtmlHelper html,
            PagingOptions options,
            int currentPage,
            int pageCount,
            RouteValueDictionary routeValues)
        {
            var page = new StringBuilder();
 
            if (!options.DisplayLinkToNextPage)
            {
                return page.ToString();
            }
 
            if (currentPage != pageCount && currentPage < pageCount)
            {
                routeValues[options.PageParameterName] = currentPage + 1;
                var li = new TagBuilder("li")
                {
                    InnerHtml = html.RouteLink(options.LinkToNextPageFormat, routeValues).ToString()
                };
                page.Append(li);
            }
            else
            {
                var li = new TagBuilder("li");
                var next = new TagBuilder("a") { InnerHtml = options.LinkToNextPageFormat };
                next.Attributes.Remove("href");
                next.Attributes.Add("style", "cursor: pointer;");
                li.InnerHtml = next.ToString();
                page.Append(li);
            }
 
            return page.ToString();
        }
 
        /// <summary>
        /// Lasts the page.
        /// </summary>
        /// <param name="html">The HTML.</param>
        /// <param name="options">The options.</param>
        /// <param name="lastPageToDisplay">The last page to display.</param>
        /// <param name="pageCount">The page count.</param>
        /// <param name="routeValues">The route values.</param>
        private static string LastPage(HtmlHelper html,
            PagingOptions options,
            int lastPageToDisplay,
            int pageCount,
            RouteValueDictionary routeValues)
        {
            var page = new StringBuilder();
 
            if (!options.DisplayLinkToLastPage)
            {
                return page.ToString();
            }
 
            if (lastPageToDisplay < pageCount)
            {
                routeValues[options.PageParameterName] = pageCount;
                var li = new TagBuilder("li")
                {
                    InnerHtml = html.RouteLink(options.LinkToLastPageFormat, routeValues).ToString()
                };
                page.Append(li);
            }
            else
            {
                var li = new TagBuilder("li");
                var last = new TagBuilder("a") { InnerHtml = options.LinkToLastPageFormat };
                last.Attributes.Remove("href");
                last.Attributes.Add("style", "cursor: pointer;");
                li.InnerHtml = last.ToString();
                page.Append(li);
            }
 
            return page.ToString();
        }
 
        /// <summary>
        /// Pages the count and current location.
        /// </summary>
        /// <param name="options">The options.</param>
        /// <param name="currentPage">The current page.</param>
        /// <param name="pageCount">The page count.</param>
        /// <returns></returns>
        private static string PageCountAndCurrentLocation(
            PagingOptions options,
            int currentPage,
            int pageCount)
        {
            var page = new StringBuilder();
 
            if (!options.DisplayPageCountAndCurrentLocation) return page.ToString();
            var li = new TagBuilder("li");
            if (!string.IsNullOrWhiteSpace(options.TextElementClass))
            {
                li.AddCssClass(options.TextElementClass);
            }
            li.SetInnerText(string.Format(options.PageCountAndCurrentLocationFormat, currentPage, pageCount));
            page.Append(li);
 
            return page.ToString();
        }
 
        /// <summary>
        /// Totals the item count.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="options">The options.</param>
        /// <returns></returns>
        private static string TotalItemCount(IPagedList list, PagingOptions options)
        {
            var page = new StringBuilder();
 
            if (options.DisplayTotalItemCount)
            {
                var li = new TagBuilder("li");
                if (!string.IsNullOrWhiteSpace(options.TextElementClass))
                {
                    li.AddCssClass(options.TextElementClass);
                }
                li.SetInnerText(string.Format(options.TotalItemsFormat, list.TotalItemCount));
                page.Append(li);
            }
 
            return page.ToString();
        }
 
    }
}

 

接著我們就是要使用上面兩個建立的類別以及 PagedList, PagedList.Mvc 去完成分頁功能,

Pagination.css

 
ol, ul {
    list-style: none;
}
 
.paginate {
    display: block;
    width: 100%;
    font-size: 12px;
}
 
    /** 1st pagination **/
    .paginate.pag1 { /* first page styles */
    }
 
        .paginate.pag1 li {
            font-weight: bold;
        }
 
            .paginate.pag1 li a {
                display: block;
                float: left;
                color: #717171;
                background: #e9e9e9;
                text-decoration: none;
                padding: 5px 7px;
                margin-right: 6px;
                border-radius: 3px;
                border: solid 1px #c0c0c0;
                box-shadow: inset 0px 1px 0px rgba(255,255,255, .7), 0px 1px 3px rgba(0,0,0, .1);
                text-shadow: 1px 1px 0px rgba(255,255,255, 0.7);
            }
 
                .paginate.pag1 li a:hover {
                    background: #eee;
                    color: #555;
                }
 
                .paginate.pag1 li a:active {
                    -webkit-box-shadow: inset -1px 2px 5px rgba(0,0,0,0.25);
                    -moz-box-shadow: inset -1px 2px 5px rgba(0,0,0,0.25);
                    box-shadow: inset -1px 2px 5px rgba(0,0,0,0.25);
                }
 
            .paginate.pag1 li.single, .paginate.pag1 li.current {
                display: block;
                float: left;
                border: solid 1px #c0c0c0;
                padding: 5px 7px;
                margin-right: 6px;
                border-radius: 3px;
                color: #444;
            }
 
 
 
    /** 2nd pagination **/
    /* resource: http://pixelsdaily.com/resources/photoshop/psds/minimal-pagination/ */
    .paginate.pag2 { /* second page styles */
    }
 
        .paginate.pag2 li {
            font-weight: bold;
        }
 
            .paginate.pag2 li a {
                display: block;
                float: left;
                color: #585858;
                text-decoration: none;
                padding: 6px 11px;
                margin-right: 6px;
                border-radius: 3px;
                border: 1px solid #ddd;
                background-color: #eee;
                background-image: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#eee));
                background-image: -webkit-linear-gradient(top, #f7f7f7, #eee);
                background-image: -moz-linear-gradient(top, #f7f7f7, #eee);
                background-image: -ms-linear-gradient(top, #f7f7f7, #eee);
                background-image: -o-linear-gradient(top, #f7f7f7, #eee);
                background-image: linear-gradient(top, #f7f7f7, #eee);
                -webkit-box-shadow: 2px 2px 4px -1px rgba(0,0,0, .55);
                -moz-box-shadow: 2px 2px 4px -1px rgba(0,0,0, .55);
                box-shadow: 2px 2px 4px -1px rgba(0,0,0, .55);
            }
 
                .paginate.pag2 li a:hover {
                    color: #3280dc;
                }
 
                .paginate.pag2 li a:active {
                    position: relative;
                    top: 1px;
                    -webkit-box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                    -moz-box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                    box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                }
 
            .paginate.pag2 li.single, .paginate.pag2 li.current {
                display: block;
                float: left;
                padding: 6px 11px;
                padding-top: 8px;
                margin-right: 6px;
                border-radius: 3px;
                color: #676767;
            }
 
 
 
 
    /** 3rd pagination **/
    /* resource: http://pixelsdaily.com/resources/photoshop/psds/psd-slick-pagination-links/ */
    .paginate.pag3 { /* third page styles */
    }
 
        .paginate.pag3 li {
            font-weight: bold;
        }
 
            .paginate.pag3 li a {
                display: block;
                float: left;
                text-decoration: none;
                padding: 6px 11px;
                margin-right: 6px;
                border-radius: 3px;
                color: #fff;
                text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.5);
                border: 1px solid #43505e;
                background: #556270;
                background: -moz-linear-gradient(top, #556270 0%, #444d57 100%);
                background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#556270), color-stop(100%,#444d57));
                background: -webkit-linear-gradient(top, #556270 0%,#444d57 100%);
                background: -o-linear-gradient(top, #556270 0%,#444d57 100%);
                background: -ms-linear-gradient(top, #556270 0%,#444d57 100%);
                background: linear-gradient(to bottom, #556270 0%,#444d57 100%);
                filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#556270', endColorstr='#444d57',GradientType=0 );
                -moz-box-shadow: inset 0 3px 0px -2px rgba(255, 255, 255, .3);
                -webkit-box-shadow: inset 0 3px 0px -2px rgba(255, 255, 255, .3);
                box-shadow: inset 0 3px 0px -2px rgba(255, 255, 255, .3);
            }
 
                .paginate.pag3 li a:hover {
                    background: #556270;
                    background: -moz-linear-gradient(top, #556270 0%, #5b6774 100%);
                    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#556270), color-stop(100%,#5b6774));
                    background: -webkit-linear-gradient(top, #556270 0%,#5b6774 100%);
                    background: -o-linear-gradient(top, #556270 0%,#5b6774 100%);
                    background: -ms-linear-gradient(top, #556270 0%,#5b6774 100%);
                    background: linear-gradient(to bottom, #556270 0%,#5b6774 100%);
                    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#556270', endColorstr='#5b6774',GradientType=0 );
                }
 
                .paginate.pag3 li a:active {
                    background: #414952;
                    background: -moz-linear-gradient(top, #414952 0%, #555e68 100%);
                    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#414952), color-stop(100%,#555e68));
                    background: -webkit-linear-gradient(top, #414952 0%,#555e68 100%);
                    background: -o-linear-gradient(top, #414952 0%,#555e68 100%);
                    background: -ms-linear-gradient(top, #414952 0%,#555e68 100%);
                    background: linear-gradient(to bottom, #414952 0%,#555e68 100%);
                    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#414952', endColorstr='#555e68',GradientType=0 );
                }
 
            .paginate.pag3 li.single, .paginate.pag3 li.current {
                display: block;
                float: left;
                text-decoration: none;
                padding: 6px 11px;
                margin-right: 6px;
                border-radius: 3px;
                color: #fff;
                text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.5);
                border: 1px solid #616c78;
                background: #838d98;
                -moz-box-shadow: inset 0 3px 0px -2px rgba(255, 255, 255, .3);
                -webkit-box-shadow: inset 0 3px 0px -2px rgba(255, 255, 255, .3);
                box-shadow: inset 0 3px 0px -2px rgba(255, 255, 255, .3);
            }
 
 
 
    /** 4th pagination **/
    /* resource: http://pixelsdaily.com/resources/photoshop/psds/flat-pagination-interface/ */
    .paginate.pag4 { /* fourth page styles */
        font-size: 1.4em;
    }
 
        .paginate.pag4 li {
            font-weight: bold;
        }
 
            .paginate.pag4 li a {
                display: block;
                float: left;
                color: #a2c49e;
                text-decoration: none;
                padding: 9px 12px;
                margin-right: 6px;
                border-radius: 16px;
                background: #363842;
                -webkit-transition: all 0.3s linear;
                -moz-transition: all 0.3s linear;
                transition: all 0.3s linear;
            }
 
                .paginate.pag4 li a:hover {
                    color: #fff;
                }
 
                .paginate.pag4 li a:active {
                    -webkit-box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                    -moz-box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                    box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                }
 
            .paginate.pag4 li.navpage a {
                padding: 9px 13px;
                background: #607c5d;
                color: #fff;
            }
 
                .paginate.pag4 li.navpage a:hover {
                    background: #486f43;
                }
 
            .paginate.pag4 li.single, .paginate.pag4 li.current {
                display: block;
                float: left;
                padding: 9px 12px;
                margin-right: 6px;
                border-radius: 16px;
                color: #607c5d;
                background: #d0dfcf;
            }
 
 
 
    /** 5th pagination (dark) **/
    .paginate.pag5 { /* fifth page styles */
        font-size: 1.4em;
        padding: 9px 8px;
        background: #373943;
        -webkit-border-radius: 3px;
        -moz-border-radius: 3px;
        border-radius: 3px;
    }
 
        .paginate.pag5 li {
            font-weight: bold;
        }
 
            .paginate.pag5 li a {
                display: block;
                float: left;
                color: #5ea25a;
                text-decoration: none;
                padding: 9px 12px;
                margin-right: 6px;
                border-radius: 16px;
                background: #fff;
                -webkit-transition: all 0.3s linear;
                -moz-transition: all 0.3s linear;
                transition: all 0.3s linear;
            }
 
                .paginate.pag5 li a:hover {
                    color: #4f664e;
                    background: #c9dec8;
                }
 
                .paginate.pag5 li a:active {
                    -webkit-box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                    -moz-box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                    box-shadow: 1px 1px 3px -1px rgba(0,0,0, .55);
                }
 
            .paginate.pag5 li.navpage a {
                padding: 9px 13px;
                background: #c8eac6;
                color: #4f664e;
            }
 
                .paginate.pag5 li.navpage a:hover {
                    color: #414e40;
                    background: #a4c6a2;
                }
 
            .paginate.pag5 li.current {
                background: #505362;
            }
 
            .paginate.pag5 li.single, .paginate.pag5 li.current {
                display: block;
                float: left;
                padding: 9px 12px;
                margin-right: 6px;
                border-radius: 16px;
                color: #fff;
            }
 
 
/** clearfix **/
.clearfix:after {
    content: ".";
    display: block;
    clear: both;
    visibility: hidden;
    line-height: 0;
    height: 0;
}
 
.clearfix {
    display: inline-block;
}
 
html[xmlns] .clearfix {
    display: block;
}
 
* html .clearfix {
    height: 1%;
}

 

View 檢視頁面

後端的 Controller 與 Action 方法就如同一般使用 PagedList 的方式一樣,使用 ToPagedList() 或 StaticPagedList<T>() 方法都可以,而前端頁面上去建立 PagingOptions 類別的物件,在這個物件裡就去設定 Pager 的各種樣式、顯示文字等。

image

image

檢視頁面所使用的 Model 型別還是一樣要用 IPagedList<T>.

image

而 Pager 的使用方式則是相當簡單,

image

以上的幾個步驟就完成分頁功能的設定。

 

顯示

image

image

image

 

其他樣式

image

image

 


有些功能並不一定需要我們從頭到尾地去把程式給實作出來,像這一篇就是基於 PagedList, PagedList.Mvc 的基礎,然後再去實作出我們所想要的分頁功能,我除非必要,不然我不太會去修改套件原本的程式碼,因為我不希望造成太多的混亂,因為原本的程式就寫好好的,也可以正常運作,所以我才會選擇另外作一個自己的 Pager,而且往後如果需要增加分頁的功能時,只需要去修改我們自己的程式就好。

最後要說的是,除非必要,或是你真的很想要練功,我真的建議不要從頭到尾去搞一套自己的分頁功能機制,就成本效益來說,真的划不來呀。

 

參考連結

https://github.com/troygoode/PagedList

Building a Custom CSS3 Pagination User Interface | Design Shack

 

以上

2 則留言:

  1. 使用PagedList组件的时候,遇到过一个问题,用Json.Net序列化PagedList的时候,发现结果不对,后来才知道Json.Net发现对象继承IEnumable接口的时候,直接对其作对象的集合[{},{},{}]方式处理了

    回覆刪除
    回覆
    1. Hello,
      我倒是沒有對 PagedList 的處理結果去做序列化 JSON 的經驗,
      感謝你的回應。

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。