@@ -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