本文中,讓我們嘗試構建自定義 HTML Hepler以在 .NET Core MVC 應用程序中提供分頁。首先對不熟悉的人簡單介紹一下,什么是HTML Helper(助手):
在Web應用程序中,如果要顯示大量記錄,則需要提供分頁。在本文中,我們通過創建自定義 HTML Helper 在 .NET Core MVC 應用程序中實現分頁。為了簡單起見,我們只能使用數字來表示數據。
假設我們需要在多頁中顯示 55 條記錄,每頁有 10 個項目,如上所示。
打開 Visual Studio 2019 > 創建 .NET Core MVC 應用程序,如下所示。
項目命名為 HTMLHelpersApp。
選擇 .NET 框架版本。
創建所需的模型和幫助文件。
在 Number.cs 中添加代碼。該模型捕獲用戶輸入。它只有一個屬性:“InputNumber”。
using System;
using System.ComponentModel.DataAnnotations;
namespace HTMLHelpersApp.Models
{
public class Number
{
//validation for required, only numbers, allowed range-1 to 500
[Required(ErrorMessage = "Value is Required!. Please enter value between 1 and 500.")]
[RegularExpression(@"^\d+$", ErrorMessage = "Only numbers are allowed. Please enter value between 1 and 500.")]
[Range(1, 500, ErrorMessage = "Please enter value between 1 and 500.")]
public int InputNumber = 1;
}
}
現在讓我們添加一個公共類 PageInfo.cs。創建新文件夾 Common 并添加 PageInfo.cs 類。
在 PageInfo.cs 中添加代碼:
根據總項目數和每頁項目數,計算頁面的總頁數、第一個項目和最后一個項目。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace HTMLHelpersApp.Common
{
public class PageInfo
{
public int TotalItems { get; set; }
public int ItemsPerPage { get; set; }
public int CurrentPage { get; set; }
public PageInfo()
{
CurrentPage = 1;
}
//starting item number in the page
public int PageStart
{
get { return ((CurrentPage - 1) * ItemsPerPage + 1); }
}
//last item number in the page
public int PageEnd
{
get
{
int currentTotal = (CurrentPage - 1) * ItemsPerPage + ItemsPerPage;
return (currentTotal < TotalItems ? currentTotal : TotalItems);
}
}
public int LastPage
{
get { return (int)Math.Ceiling((decimal)TotalItems / ItemsPerPage); }
}
}
}
現在我們來到最重要的部分:創建自定義 HTML 助手。
public static IHtmlContent PageLinks(this IHtmlHelper htmlHelper, PageInfo pageInfo, Func<int, string> PageUrl)
5.取2個參數
使用標簽構建器創建錨標簽。
TagBuilder tag = new TagBuilder("a");
Add attributes
tag.MergeAttribute("href", hrefValue);
tag.InnerHtml.Append(" "+ innerHtml + " ");
樣式也可以用作屬性。
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Text;
namespace HTMLHelpersApp.Common
{
public static class PagingHtmlHelpers
{
public static IHtmlContent PageLinks(this IHtmlHelper htmlHelper, PageInfo pageInfo, Func<int, string> PageUrl)
{
StringBuilder pagingTags = new StringBuilder();
//Prev Page
if (pageInfo.CurrentPage > 1)
{
pagingTags.Append(GetTagString("Prev", PageUrl(pageInfo.CurrentPage - 1)));
}
//Page Numbers
for (int i = 1; i <= pageInfo.LastPage; i++)
{
pagingTags.Append(GetTagString(i.ToString(), PageUrl(i)));
}
//Next Page
if (pageInfo.CurrentPage < pageInfo.LastPage)
{
pagingTags.Append(GetTagString("Next", PageUrl(pageInfo.CurrentPage + 1)));
}
//paging tags
return new HtmlString(pagingTags.ToString());
}
private static string GetTagString(string innerHtml, string hrefValue)
{
TagBuilder tag = new TagBuilder("a"); // Construct an <a> tag
tag.MergeAttribute("class","anchorstyle");
tag.MergeAttribute("href", hrefValue);
tag.InnerHtml.Append(" "+ innerHtml + " ");
using (var sw = new System.IO.StringWriter())
{
tag.WriteTo(sw, System.Text.Encodings.Web.HtmlEncoder.Default);
return sw.ToString();
}
}
}
}
在“Models”文件夾中添加一個新類“ShowPaging.cs”。
using HTMLHelpersApp.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace HTMLHelpersApp.Models
{
public class ShowPaging
{
//validation for required, only numbers, allowed range-1 to 500
[Required(ErrorMessage = "Value is Required!. Please enter value between 1 and 500.")]
[RegularExpression(@"^\d+$", ErrorMessage = "Only positive numbers are allowed. Please enter value between 1 and 500.")]
[Range(1, 500, ErrorMessage = "Please enter value between 1 and 500.")]
public int InputNumber { get; set; }
public List<string> DisplayResult { get; set; }
public PageInfo PageInfo;
}
}
添加一個新控制器:“HTMLHelperController”
右鍵單擊控制器文件夾并在上下文菜單中選擇控制器。
選擇“MVCController-Empty”。
在“HTMLHelperController”中添加代碼。
using HTMLHelpersApp.Common;
using HTMLHelpersApp.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace HTMLHelpersApp.Controllers
{
public class HTMLHelperController : Controller
{
private const int PAGE_SIZE = 10;
public IActionResult Number()
{
return View();
}
public IActionResult ShowPaging(ShowPaging model, int page = 1, int inputNumber = 1)
{
if (ModelState.IsValid)
{
var displayResult = new List<string>();
string message;
//set model.pageinfo
model.PageInfo = new PageInfo();
model.PageInfo.CurrentPage = page;
model.PageInfo.ItemsPerPage = PAGE_SIZE;
model.PageInfo.TotalItems = inputNumber;
//Set model.displayresult - numbers list
for (int count = model.PageInfo.PageStart; count <= model.PageInfo.PageEnd; count++)
{
message = count.ToString();
displayResult.Add(message.Trim());
}
model.DisplayResult = displayResult;
}
//return view model
return View(model);
}
}
}
在 Views 文件夾中創建一個新文件夾“HTMLHelper”,并創建一個新視圖“Number.cshtml”。
在“Number.cshtml”中添加代碼。
@model HTMLHelpersApp.Models.Number
<h4>Number</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="ShowPaging" method="get">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<input asp-for="InputNumber" class="form-control"/>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</form>
</div>
</div>
同樣,創建一個新視圖“ShowPaging.cshtml”。
@model HTMLHelpersApp.Models.ShowPaging
@using HTMLHelpersApp.Common
<link rel="stylesheet" href ="~/css/anchorstyles.css"/>
<form>
<h4>Show Paging</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<dl class="row">
<dt class="col-sm-2">
<b>Number: </b> @Html.DisplayFor(model => model.InputNumber)
</dt>
<dd>
<a asp-action="Number">Change Number</a>
</dd>
</dl>
<div>
@if (Model != null && Model.DisplayResult != null)
{
<ul>
@foreach (var item in Model.DisplayResult)
{
<li>@Html.Raw(item)</li>
}
</ul>
<div>
@Html.PageLinks(@Model.PageInfo, x => Url.Action("ShowPaging",
new { page = x.ToString(), inputNumber = @Model.InputNumber }))
</div>
}
</div>
</form>
解決方案資源管理器如下所示:
在“startup.cs”中配置默認控制器和操作。
編譯并運行應用程序,輸入數字 35。
點擊提交。
你會在底部看到分頁,每頁顯示10個數字,一共4頁,且每頁都一個鏈接。
qPaginator是一個簡潔、高度自定義的jQuery分頁組件 !而且自帶BootStrap的樣式!當然你入股不喜歡BootStrap的樣式,完全可以自定義!
GitHub地址: https://github.com/DangJin/jqPaginator!
好了我們接下來介紹下這么優美的東西該如何使用吧!
引入Js文件
這里需要說明的是因為內置BootStrap樣式,所以需要引入BootStrap的Css樣式哦!
配置參數
參數 | 默認值 | 說明 |
---|---|---|
totalPages | 0 | 設置分頁的總頁數 |
totalCounts | 0 | 設置分頁的總條目數 |
pageSize | 0 | 設置每一頁的條目數注意:要么設置totalPages,要么設置totalCounts + pageSize,否則報錯;設置了totalCounts和pageSize后,會自動計算出totalPages。 |
currentPage | 1 | 設置當前的頁碼 |
visiblePages | 7 | 設置最多顯示的頁碼數(例如有100也,當前第1頁,則顯示1 - 7頁) |
disableClass | 'disabled' | 設置首頁,上一頁,下一頁,末頁的“禁用狀態”樣式 |
activeClass | 'active' | 設置當前頁碼樣式 |
first | bootstrap風格 | 設置“首頁”的Html結構 |
prev | bootstrap風格 | 設置“上一頁”的Html結構 |
next | bootstrap風格 | 設置“下一頁”的Html結構 |
last | bootstrap風格 | 設置“末頁”的Html結構 |
page | bootstrap風格 | 設置頁碼的Html結構,其中可以使用{{page}}代表當前頁,{{totalPages}}代表總頁數,{{totalCounts}}代表總條目數(例如:上面的“極簡風格”的Demo,就是使用了{{占位符}},并將visiblePages設為1實現的。)注意:first、prev、next、last。page只要設置一個,其余未設置的會變為空。 |
wrapper | (無) | 分頁結構的Html包裹,例如:<div class="your class"></div>,一般不會用到 |
onPageChange | (無) | 回調函數,當換頁時觸發(包括初始化第一頁的時候),會傳入兩個參數:1、“目標頁"的頁碼,Number類型2、觸發類型,可能的值:“init”(初始化),“change”(點擊分頁) |
如果不是自定義樣式,用默認的記得一定要加這個屬性 wrapper 如果不加,會出現這種奇葩的情況
BootStrap默認wrapper 是<nav></nav>
當報表展示的數據量比較多的時候,有兩種辦法可以有效提升預覽速度。
一種情況是sql查詢速度比較快,頁面展示比較慢。此時直接使用帆軟內置的分頁預覽方式就可以大幅提升預覽速度。
另一種情況是,sql查詢本身就比較慢。這種就需要通過sql分頁來提升預覽速度。
帆軟本身提供行式引擎來解決這種問題,不過使用行式引擎有其自身的局限性,具體詳情可以查看帆軟幫助文檔:啟用行式引擎執行層式報表- FineReport幫助文檔 - 全面的報表使用教程和學習資料
自定義帆軟的工具欄,使用js來實現對應的翻頁功能,并且提供兩個參數來供sql調用,能滿足所有數據庫sql分頁的使用場景。最終效果如下:
1、創建分頁sql
sql語句如下:
select * from 銷量 order by 銷量
${if(len(pageno)=0,"","limit "+((pageno-1)*pagesize)+","+pagesize)}
同時創建一個計算總行數和總頁數的sql,需要注意,數據集名稱命名為pagetool,總行數重新名為totalcnt,總頁數重命名為totalpage,后面js中調用會用到。
select count(1) as totalcnt,
ceiling(count(1)*1.0/${pagesize}) as totalpage
from 銷量
2、報表設計
報表設計沒有限制,根據實際項目需求設計。這里的設計如下:
3、引入js文件
點擊工具欄進行分頁的時候,需要向頁面傳遞參數,并刷新頁面。這里采用動態參數傳參的方式,因為多處自定義事件均使用到傳參,因此將它定義成一個函數,以實現復用。代碼如下:
var reload=function(param){
FR.ajax({
url:'/webroot/decision/view/report?op=fr_dialog&cmd=parameters_dynamic',
type:'POST',
data:param,
headers: {sessionID:FR.SessionMgr.getSessionID()},
complete:function(res, status){
if(window.FR && FR.Chart && FR.Chart.WebUtils){
FR.Chart.WebUtils.clearCharts(); }
if(window.FR && FR.destroyDialog) {
FR.destroyDialog(); }
_g().loadContentPane();
}
})
}
將其保存為reload.js文件,并在模板>模板web屬性>引用JavaScript處將其導入,如下所示:
5、自定義工具欄
考慮到實現效果后可以自定義每頁顯示的條數,導致報表展示的頁面大小無法估計。因此使用填報預覽的方式來實現。
1)打開模板>模板web屬性>填報頁面設置,選擇為該模板單獨設置,將默認的工具欄按鈕全部清除掉,然后依次添加兩個自定義按鈕,一個郵件按鈕,四個自定義按鈕,一個PDF按鈕。如下所示:
2)為自定義按鈕重命名并添加自定義事件
如圖所示,六個自定義的重命名分別為
①重命名:首頁,自定義事件如下:
reload({"pageno":1})
②重命名:上一頁,自定義事件如下:
var pageno = FR.remoteEvaluate("=$pageno");
reload({"pageno":pageno-1});
③重命名:下一頁,自定義事件如下:
var pageno = FR.remoteEvaluate("=$pageno");
reload({"pageno":pageno*1+1})
④重命名:末頁,自定義事件如下:
var totalpage = FR.remoteEvaluate("=value('pagetool',2,1)");
reload({"pageno":totalpage});
⑤重命名:導出Excel,自定義事件如下:
var url = "${servletURL}?viewlet=${reportName}&format=excel&pageno=";
window.location=encodeURI(encodeURI(url));
⑥重命名:數據總量,無自定義事件。
5、添加加載結束事件
在模板>模板web屬性>填報頁面設置>為該模板單獨設置中,添加加載結束事件,如下圖所示
其中代碼如下:
setTimeout(function(){
// 定義變量獲取總行數、總頁數、頁碼、每頁顯示行數
var totalcnt = FR.remoteEvaluate("=value('pagetool',1,1)");
var totalpage = FR.remoteEvaluate("=value('pagetool',2,1)");
var pageno = FR.remoteEvaluate("=$pageno");
var pagesize = FR.remoteEvaluate("=$pagesize");
//定義當前頁和每頁顯示行數的html代碼
var currentpageStr = "<input id='currentpage' min='1' type='number' style='width:50px;'/><label id='totalpage' style='font:400 13.3333px Arial;'></label>";
var pagesizeStr = "<label style='font:400 13.3333px Arial;'>每頁顯示條數:</label><input id='pagesize' min='10' max='100' type='number' style='width:50px'/>";
//將email按鈕和pdf按鈕替換成當前頁和每頁顯示行數,并設置按鈕屬性
$("div[widgetname=Email]").replaceWith(currentpageStr);
$("div[widgetname=PDF]").replaceWith(pagesizeStr);
$("#currentpage").val(pageno);
$("#currentpage").attr("max",totalpage);
$("#totalpage").text(" / "+totalpage);
$("#pagesize").val(pagesize);
_g().toolbar.options.items[6].setValue("數據總量:"+totalcnt);
//當前頁的值有變化時觸發的操作
$("#currentpage").change(function(){
var val = $(this).val();
if(val <1 || val>totalpage){
$(this).val(pageno);
}else{
reload({"pageno":val})
}
})
//每頁顯示行數的值有變化時觸發的操作
$("#pagesize").change(function(){
var val = $(this).val();
if(val <10 || val>100){
$(this).val(pagesize);
}else{
reload({"pagesize":val})
}
})
//當頁碼為1時,首頁和上一頁不可用
if(pageno == 1){
_g().toolbar.options.items[0].setEnable(false);
_g().toolbar.options.items[1].setEnable(false);
}
//當頁碼等于最后一頁時,下一頁和末頁不可用
if(pageno == totalpage){
_g().toolbar.options.items[3].setEnable(false);
_g().toolbar.options.items[4].setEnable(false);
}
},10)
11.0.5(Build#persist-2022.06.15.17.11.21.865)
*請認真填寫需求信息,我們會在24小時內與您取得聯系。