@@ -38,6 +38,17 @@ public partial class MultiSelect<TValue>
3838 . AddClass ( "d-none" , SelectedItems . Count != 0 )
3939 . Build ( ) ;
4040
41+ private string ? SearchClassString => CssBuilder . Default ( "search" )
42+ . AddClass ( "show" , ShowSearch )
43+ . Build ( ) ;
44+
45+ /// <summary>
46+ /// 获得 SearchLoadingIcon 图标字符串
47+ /// </summary>
48+ private string ? SearchLoadingIconString => CssBuilder . Default ( "icon searching-icon" )
49+ . AddClass ( SearchLoadingIcon )
50+ . Build ( ) ;
51+
4152 /// <summary>
4253 /// 获得/设置 绑定数据集
4354 /// </summary>
@@ -51,13 +62,6 @@ public partial class MultiSelect<TValue>
5162 [ Parameter ]
5263 public RenderFragment < SelectedItem > ? ItemTemplate { get ; set ; }
5364
54- /// <summary>
55- /// 获得/设置 组件 PlaceHolder 文字 默认为 点击进行多选 ...
56- /// </summary>
57- [ Parameter ]
58- [ NotNull ]
59- public string ? PlaceHolder { get ; set ; }
60-
6165 /// <summary>
6266 /// 获得/设置 是否显示关闭按钮 默认为 true 显示
6367 /// </summary>
@@ -191,10 +195,23 @@ public partial class MultiSelect<TValue>
191195 [ NotNull ]
192196 private IStringLocalizer < MultiSelect < TValue > > ? Localizer { get ; set ; }
193197
198+ private List < SelectedItem > ? _itemsCache ;
199+
200+ private List < SelectedItem > Rows
201+ {
202+ get
203+ {
204+ _itemsCache ??= string . IsNullOrEmpty ( SearchText ) ? GetRowsByItems ( ) : GetRowsBySearch ( ) ;
205+ return _itemsCache ;
206+ }
207+ }
208+
194209 private string ? PreviousValue { get ; set ; }
195210
196211 private string ? PlaceholderString => SelectedItems . Count == 0 ? PlaceHolder : null ;
197212
213+ private string ? ScrollIntoViewBehaviorString => ScrollIntoViewBehavior == ScrollIntoViewBehavior . Smooth ? null : ScrollIntoViewBehavior . ToDescriptionString ( ) ;
214+
198215 /// <summary>
199216 /// OnParametersSet 方法
200217 /// </summary>
@@ -208,21 +225,22 @@ protected override void OnParametersSet()
208225 ClearText ??= Localizer [ nameof ( ClearText ) ] ;
209226 MinErrorMessage ??= Localizer [ nameof ( MinErrorMessage ) ] ;
210227 MaxErrorMessage ??= Localizer [ nameof ( MaxErrorMessage ) ] ;
228+ NoSearchDataText ??= Localizer [ nameof ( NoSearchDataText ) ] ;
211229
212230 DropdownIcon ??= IconTheme . GetIconByKey ( ComponentIcons . MultiSelectDropdownIcon ) ;
213231 ClearIcon ??= IconTheme . GetIconByKey ( ComponentIcons . MultiSelectClearIcon ) ;
214232
215233 ResetItems ( ) ;
216- OnSearchTextChanged ??= text => Items . Where ( i => i . Text . Contains ( text , StringComparison . OrdinalIgnoreCase ) ) ;
217234 ResetRules ( ) ;
218235
236+ _itemsCache = null ;
219237 // 通过 Value 对集合进行赋值
220238 if ( PreviousValue != CurrentValueAsString )
221239 {
222240 PreviousValue = CurrentValueAsString ;
223241 var list = CurrentValueAsString . Split ( ',' , StringSplitOptions . RemoveEmptyEntries ) ;
224242 SelectedItems . Clear ( ) ;
225- SelectedItems . AddRange ( GetData ( ) . Where ( item => list . Any ( i => i == item . Value ) ) ) ;
243+ SelectedItems . AddRange ( Rows . Where ( item => list . Any ( i => i == item . Value ) ) ) ;
226244 }
227245 }
228246
@@ -241,7 +259,25 @@ protected override void OnAfterRender(bool firstRender)
241259 /// <inheritdoc/>
242260 /// </summary>
243261 /// <returns></returns>
244- protected override Task InvokeInitAsync ( ) => InvokeVoidAsync ( "init" , Id , Interop , nameof ( ToggleRow ) ) ;
262+ protected override Task InvokeInitAsync ( ) => InvokeVoidAsync ( "init" , Id , Interop , new { ConfirmMethodCallback = nameof ( ConfirmSelectedItem ) , SearchMethodCallback = nameof ( TriggerOnSearch ) , TriggerEditTag = nameof ( TriggerEditTag ) , ToggleRow = nameof ( ToggleRow ) } ) ;
263+
264+ private List < SelectedItem > GetRowsByItems ( )
265+ {
266+ var items = new List < SelectedItem > ( ) ;
267+ if ( Items != null )
268+ {
269+ items . AddRange ( Items ) ;
270+ }
271+ return items ;
272+ }
273+
274+ private List < SelectedItem > GetRowsBySearch ( )
275+ {
276+ var items = OnSearchTextChanged ? . Invoke ( SearchText ) ?? FilterBySearchText ( GetRowsByItems ( ) ) ;
277+ return items . ToList ( ) ;
278+ }
279+
280+ private IEnumerable < SelectedItem > FilterBySearchText ( IEnumerable < SelectedItem > source ) => source . Where ( i => i . Text . Contains ( SearchText , StringComparison ) ) ;
245281
246282 /// <summary>
247283 /// FormatValueAsString 方法
@@ -254,6 +290,22 @@ protected override void OnAfterRender(bool firstRender)
254290
255291 private bool _isToggle ;
256292
293+ /// <summary>
294+ /// 客户端回车回调方法
295+ /// </summary>
296+ /// <param name="index"></param>
297+ /// <returns></returns>
298+ [ JSInvokable ]
299+ public async Task ConfirmSelectedItem ( int index )
300+ {
301+ var rows = Rows ;
302+ if ( index < rows . Count )
303+ {
304+ await ToggleRow ( rows [ index ] . Value ) ;
305+ StateHasChanged ( ) ;
306+ }
307+ }
308+
257309 /// <summary>
258310 /// 切换当前选项方法
259311 /// </summary>
@@ -270,7 +322,7 @@ public async Task ToggleRow(string val)
270322 }
271323 else
272324 {
273- var d = GetData ( ) . FirstOrDefault ( i => i . Value == val ) ;
325+ var d = Rows . FirstOrDefault ( i => i . Value == val ) ;
274326 if ( d != null )
275327 {
276328 SelectedItems . Add ( d ) ;
@@ -299,7 +351,7 @@ public async Task<bool> TriggerEditTag(string val)
299351 }
300352 else if ( ! string . IsNullOrEmpty ( val ) )
301353 {
302- ret = GetData ( ) . Find ( i => i . Text . Equals ( val , StringComparison . OrdinalIgnoreCase ) ) ?? new SelectedItem ( val , val ) ;
354+ ret = Rows . Find ( i => i . Text . Equals ( val , StringComparison . OrdinalIgnoreCase ) ) ?? new SelectedItem ( val , val ) ;
303355 }
304356 if ( ret != null )
305357 {
@@ -405,7 +457,7 @@ public async Task Clear()
405457 public async Task SelectAll ( )
406458 {
407459 SelectedItems . Clear ( ) ;
408- SelectedItems . AddRange ( GetData ( ) ) ;
460+ SelectedItems . AddRange ( Rows ) ;
409461 await SetValue ( ) ;
410462 }
411463
@@ -415,7 +467,7 @@ public async Task SelectAll()
415467 /// <returns></returns>
416468 public async Task InvertSelect ( )
417469 {
418- var items = GetData ( ) . Where ( item => ! SelectedItems . Any ( i => i . Value == item . Value ) ) . ToList ( ) ;
470+ var items = Rows . Where ( item => ! SelectedItems . Any ( i => i . Value == item . Value ) ) . ToList ( ) ;
419471 SelectedItems . Clear ( ) ;
420472 SelectedItems . AddRange ( items ) ;
421473 await SetValue ( ) ;
@@ -460,16 +512,6 @@ private bool CheckCanEdit()
460512 return ret ;
461513 }
462514
463- private List < SelectedItem > GetData ( )
464- {
465- var data = Items ;
466- if ( ShowSearch && ! string . IsNullOrEmpty ( SearchText ) )
467- {
468- data = OnSearchTextChanged ( SearchText ) ;
469- }
470- return data . ToList ( ) ;
471- }
472-
473515 /// <summary>
474516 /// 客户端检查完成时调用此方法
475517 /// </summary>
@@ -508,4 +550,18 @@ private void ResetItems()
508550 }
509551 }
510552 }
553+
554+ /// <summary>
555+ /// 客户端搜索栏回调方法
556+ /// </summary>
557+ /// <param name="searchText"></param>
558+ /// <returns></returns>
559+ [ JSInvokable ]
560+ public Task TriggerOnSearch ( string searchText )
561+ {
562+ _itemsCache = null ;
563+ SearchText = searchText ;
564+ StateHasChanged ( ) ;
565+ return Task . CompletedTask ;
566+ }
511567}
0 commit comments