Skip to content
This repository was archived by the owner on Jan 5, 2024. It is now read-only.

Commit d30fbf3

Browse files
committed
已经成功显示分页控件
1 parent 9325aa6 commit d30fbf3

3 files changed

Lines changed: 201 additions & 32 deletions

File tree

doc/TDesign.Docs.Shared/Layouts/NavMenu.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<TMenuItemGroup Title="导航">
1919
<TMenuItem Link="components/breadcrumb">Breadcrum 面包屑</TMenuItem>
2020
<TMenuItem Link="components/menu">Menu 导航菜单</TMenuItem>
21+
<TMenuItem Link="components/pagination">Pagination 分页</TMenuItem>
2122
<TMenuItem Link="components/step">Steps 步骤条</TMenuItem>
2223
<TMenuItem Link="components/tab">Tabs 选项卡</TMenuItem>
2324
</TMenuItemGroup>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
@page "/components/pagination"
2+
3+
<PageHeader Title="分页 Pagination">
4+
用于模块内切换内容的控件。
5+
</PageHeader>
6+
7+
<h3>基础分页</h3>
8+
<Example Title="少量页面">
9+
<Description>最基础的分页控件,仅展示页码。建议使用在内容少于10页的轻量化分页场景。</Description>
10+
<RunContent>
11+
<TPagination @bind-Current="Page" @bind-PageSize="PageSize" @bind-Total="Total"/>
12+
</RunContent>
13+
<CodeContent>
14+
15+
</CodeContent>
16+
</Example>
17+
18+
@code{
19+
long Page { get; set; } = 1;
20+
int PageSize { get; set; } = 10;
21+
long Total { get; set; } = 100;
22+
}

src/TDesign/Components/TPagination.cs

Lines changed: 178 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,53 +5,53 @@ namespace TDesign;
55
/// 用于模块内切换内容的分页
66
/// </summary>
77
[CssClass("t-pagination")]
8-
public class TPagination:BlazorComponentBase
8+
public class TPagination : BlazorComponentBase
99
{
1010
#region 参数
1111
/// <summary>
1212
/// 设置分页组件的大小。
1313
/// </summary>
14-
[Parameter][BooleanCssClass("t-size-s","t-size-m")] public bool Small { get; set; }
14+
[Parameter][BooleanCssClass("t-size-s", "t-size-m")] public bool Small { get; set; }
1515

1616
#region Current
1717
/// <summary>
1818
/// 设置当前页码。
1919
/// </summary>
20-
[Parameter][EditorRequired]public int Current { get; set; }
20+
[Parameter][EditorRequired] public long Current { get; set; }
2121
/// <summary>
2222
/// 设置一个当页码变更时的回调方法。
2323
/// </summary>
24-
[Parameter] public EventCallback<int> CurrentChanged { get; set; }
24+
[Parameter] public EventCallback<long> CurrentChanged { get; set; }
2525
#endregion
2626

2727
#region PageSize
2828
/// <summary>
2929
/// 设置每一页的数据量。默认是 10。
3030
/// </summary>
31-
[Parameter] [EditorRequired]public int PageSize { get; set; } = 10;
31+
[Parameter][EditorRequired] public int PageSize { get; set; } = 10;
3232
/// <summary>
3333
/// 设置一个当每页数据量变更时的回调方法。
3434
/// </summary>
35-
[Parameter]public EventCallback<int> PageSizeChanged { get; set; }
35+
[Parameter] public EventCallback<int> PageSizeChanged { get; set; }
3636
#endregion
3737

3838
#region Total
3939
/// <summary>
4040
/// 设置分页的总数据量。必须要大于 0。
4141
/// </summary>
42-
[Parameter][EditorRequired]public long Total { get; set; }
42+
[Parameter][EditorRequired] public long Total { get; set; }
4343
/// <summary>
4444
/// 设置一个当总数据量变化时的回调方法。
4545
/// </summary>
46-
[Parameter]public EventCallback<long> TotalChanged { get; set; }
46+
[Parameter] public EventCallback<long> TotalChanged { get; set; }
4747
/// <summary>
4848
/// 设置显示总数据量的任意内容。
4949
/// </summary>
50-
[Parameter]public RenderFragment<long>? TotalContent { get; set; }
50+
[Parameter] public RenderFragment<long>? TotalContent { get; set; }
5151
/// <summary>
5252
/// 设置一个布尔值,表示是否显示总数据量的内容。
5353
/// </summary>
54-
[Parameter]public bool ShowTotal { get; set; }
54+
[Parameter] public bool ShowTotal { get; set; } = true;
5555
#endregion
5656

5757
/// <summary>
@@ -70,13 +70,13 @@ long TotalPages
7070
get
7171
{
7272
var total = Total + PageSize - 1;
73-
if ( total <= 0 )
73+
if (total <= 0)
7474
{
7575
total = 1;
7676
}
7777

7878
var result = total / PageSize;
79-
if ( result < 0 )
79+
if (result < 0)
8080
{
8181
result = 1;
8282
}
@@ -86,64 +86,209 @@ long TotalPages
8686
#endregion
8787

8888
#region Method
89+
90+
#region Public
91+
92+
/// <summary>
93+
/// 跳转到指定页。
94+
/// </summary>
95+
/// <param name="page">要跳转的页码。</param>
96+
public async Task NavigateToPage(long page)
97+
{
98+
page = page < 1 ? 1 : page;
99+
page = page > TotalPages ? TotalPages : page;
100+
101+
Current = page;
102+
await CurrentChanged.InvokeAsync(page);
103+
await this.Refresh();
104+
}
105+
/// <summary>
106+
/// 跳转到首页。
107+
/// </summary>
108+
public Task NavigateToFirst() => NavigateToPage(1);
109+
/// <summary>
110+
/// 跳转到末页。
111+
/// </summary>
112+
public Task NavigateToLast() => NavigateToPage(TotalPages);
113+
/// <summary>
114+
/// 跳转到上一页。
115+
/// </summary>
116+
public Task NavigateToPrevious() => NavigateToPage(--Current);
117+
/// <summary>
118+
/// 跳转到下一页。
119+
/// </summary>
120+
public Task NavigateToNext() => NavigateToPage(++Current);
121+
#endregion
122+
123+
#region Protected
89124
/// <inheritdoc/>
90125
protected override void OnParametersSet()
91126
{
92127
base.OnParametersSet();
93128

94-
if ( Current <= 0 )
129+
if (Current <= 0)
95130
{
96131
throw new ArgumentException($"{nameof(Current)} 必须大于0");
97132
}
98-
if ( PageSize <= 0 )
133+
if (PageSize <= 0)
99134
{
100135
throw new ArgumentException($"{nameof(PageSize)} 必须大于0");
101136
}
102-
if ( Total <= 0 )
137+
if (Total <= 0)
103138
{
104139
throw new ArgumentException($"{nameof(Total)} 必须大于0");
105140
}
141+
142+
TotalContent ??= value => new RenderFragment(builder => builder.AddContent(0, $"共 {Total} 项数据"));
106143
}
107144

108145
protected override void AddContent(RenderTreeBuilder builder, int sequence)
109146
{
110147
BuildTotal(builder, sequence);
111-
BuildPrevOrNextBtn(builder, sequence + 1, true);
148+
149+
//上一页
150+
BuildPrevOrNextBtn(builder, sequence + 1, true, Current <= 1);
151+
112152
BuildPageNumbers(builder, sequence + 2);
113-
BuildPrevOrNextBtn(builder, sequence + 3, false);
153+
154+
//下一页
155+
BuildPrevOrNextBtn(builder, sequence + 3, false, Current >= TotalPages);
114156
}
157+
#endregion
115158

159+
#region Private
116160
/// <summary>
117161
/// 构建总数据量的元素。
118162
/// </summary>
119-
void BuildTotal(RenderTreeBuilder builder, int sequence) => builder.CreateElement(sequence, "div", TotalContent?.Invoke(Total), new { @class = "t-pagination__total" }, ShowTotal);
163+
void BuildTotal(RenderTreeBuilder builder, int sequence)
164+
=> builder.CreateElement(sequence, "div", TotalContent?.Invoke(Total), new { @class = "t-pagination__total" }, ShowTotal);
120165

121166
/// <summary>
122167
/// 构建上一页或下一页按钮。
123-
/// </summary>
124-
/// <param name="builder"></param>
125-
/// <param name="sequence"></param>
126168
/// <param name="prevOrNext"><c>true</c> 表示上一页,否则是下一页。</param>
127-
void BuildPrevOrNextBtn(RenderTreeBuilder builder, int sequence,bool prevOrNext)
169+
/// <param name="disabled">是否被禁用。</param>
170+
void BuildPrevOrNextBtn(RenderTreeBuilder builder, int sequence, bool prevOrNext, bool disabled = default)
128171
{
129172
builder.CreateElement(sequence, "div", content =>
130173
{
131174
content.CreateComponent<TIcon>(0, attributes: new { Name = prevOrNext ? IconName.ChevronLeft : IconName.ChevronRight });
132-
}, new { @class = HtmlHelper.CreateCssBuilder().Append("t-pagination__btn").Append("t-pagination__btn-prev", prevOrNext).Append("t-pagination__btn-next") });
175+
}, new
176+
{
177+
@class = HtmlHelper.CreateCssBuilder()
178+
.Append("t-pagination__btn")
179+
.Append("t-pagination__btn-prev", prevOrNext)
180+
.Append("t-pagination__btn-next", !prevOrNext)
181+
.Append("t-is-disabled", disabled)
182+
,
183+
onclick = HtmlHelper.CreateCallback(this, async () =>
184+
{
185+
if (prevOrNext)//上一页
186+
{
187+
await NavigateToPrevious();
188+
}
189+
else
190+
{
191+
await NavigateToNext();
192+
}
193+
}, !disabled)
194+
});
133195
}
134196

197+
/// <summary>
198+
/// 该方法用于构建分页的页码条的各项,例如上一页按钮,分页页码,末页按钮等。
199+
/// </summary>
200+
/// <param name="builder"></param>
201+
/// <param name="sequence"></param>
202+
/// <param name="content">显示的文本。</param>
203+
/// <param name="callback">点击的回调。</param>
204+
/// <param name="disabled">是否禁用。</param>
205+
/// <param name="additionalClass">附加的 class 样式。</param>
206+
void BuildPageItem(RenderTreeBuilder builder, int sequence, RenderFragment content, Func<Task>? callback = default, bool disabled = default, string? additionalClass = default)
207+
{
208+
builder.CreateElement(sequence, "li", content, new
209+
{
210+
@class = HtmlHelper.CreateCssBuilder()
211+
.Append("t-pagination__number")
212+
.Append("t-is-disabled", disabled)
213+
.Append(additionalClass, !string.IsNullOrEmpty(additionalClass)),
214+
onclick = HtmlHelper.CreateCallback(this, callback, callback is not null && !disabled),
215+
disabled
216+
});
217+
}
218+
219+
void BuildPageNumerItem(RenderTreeBuilder builder, int sequence, long pageNumber)
220+
{
221+
if (pageNumber == Current)
222+
{
223+
BuildPageItem(builder, sequence, number => number.AddContent(0, pageNumber), additionalClass: "t-is-current");
224+
}
225+
else
226+
{
227+
BuildPageItem(builder, sequence, number => number.AddContent(0, pageNumber), () => NavigateToPage(pageNumber));
228+
}
229+
}
230+
231+
/// <summary>
232+
/// 构建分页条。
233+
/// </summary>
135234
void BuildPageNumbers(RenderTreeBuilder builder, int sequence)
136235
{
137-
builder.CreateElement(sequence, "ul", content =>
236+
237+
//分页条
238+
builder.CreateElement(sequence + 1, "ul", content =>
138239
{
240+
#region 第一页
241+
242+
//第一页永远显示
243+
BuildPageNumerItem(content, 0, 1);
244+
245+
#endregion
246+
247+
#region 前5页
248+
if (Current > PageNumber / 2)
249+
{
250+
var backTo = PageNumber - 5;
251+
if (backTo <= 1)
252+
{
253+
backTo = 1;
254+
}
255+
BuildPageItem(content, 1, text => text.CreateComponent<TIcon>(0, attributes: new { Name = IconName.Ellipsis }), () => NavigateToPage(backTo));
256+
}
257+
#endregion
258+
259+
#region 页码条
260+
139261
var (start, end) = ComputePageNumber();
140-
for ( long i = start; i <=end; i++ )
262+
263+
//页码1 永远显示,所有从2开始
264+
//最后一页永远显示,所以结束要少一个索引
265+
266+
for (long i = start + 1; i <= end - 1; i++)
141267
{
142-
content.CreateElement((int)i, "li", i.ToString(), new { @class = "t-pagination__number" });
268+
var current = i;
269+
var contentSequence = (int)i + 30;
270+
271+
BuildPageNumerItem(content, contentSequence, current);
143272
}
273+
#endregion
144274

145-
}, new { @class = "t-pagination__pager" });
275+
#region 后5页
276+
if (Current < TotalPages - PageNumber / 2)
277+
{
278+
var nextTo = Current + 5;
279+
if (nextTo >= TotalPages)
280+
{
281+
nextTo = TotalPages;
282+
}
283+
BuildPageItem(content, 90, text => text.CreateComponent<TIcon>(0, attributes: new { Name = IconName.Ellipsis }), () => NavigateToPage(nextTo));
284+
}
285+
#endregion
286+
287+
#region 末页
288+
BuildPageNumerItem(content, 100, TotalPages);
289+
#endregion
146290

291+
}, new { @class = "t-pagination__pager" });
147292

148293
/// <summary>
149294
/// 计算分页页码的开始和结束的页码。
@@ -155,32 +300,33 @@ void BuildPageNumbers(RenderTreeBuilder builder, int sequence)
155300
var end = 0L;
156301

157302
var middle = PageNumber / 2;
158-
if ( Current <= middle )
303+
if (Current <= middle)
159304
{
160305
start = 1;
161306
end = PageNumber;
162307
}
163-
else if ( Current > middle )
308+
else if (Current > middle)
164309
{
165310
start = Current - middle;
166311
end = Current + middle;
167312
}
168-
if ( end > TotalPages )
313+
if (end > TotalPages)
169314
{
170315
end = TotalPages;
171-
if ( start + end != PageNumber - 2 )
316+
if (start + end != PageNumber - 2)
172317
{
173318
start = end - PageNumber + 2 - 1;
174319
}
175320
}
176-
if ( end <= PageNumber )
321+
if (end <= PageNumber)
177322
{
178323
start = 1;
179324
}
180325

181326
return (start, end);
182327
}
183328
}
329+
#endregion
184330

185331
#endregion
186332
}

0 commit comments

Comments
 (0)