2020-06-27 18:24:21 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using Microsoft.AspNetCore.Components;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using AntDesign.JsInterop;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using Microsoft.AspNetCore.Components.Web;
|
2020-07-31 12:43:46 +08:00
|
|
|
|
using System.Diagnostics;
|
2020-06-27 18:24:21 +08:00
|
|
|
|
|
|
|
|
|
namespace AntDesign
|
|
|
|
|
{
|
|
|
|
|
public partial class AutoComplete : AntInputComponentBase<string>
|
|
|
|
|
{
|
|
|
|
|
#region parameters
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 选项数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public IEnumerable<string> Options { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public IEnumerable<string> FormatList { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 支持清除, 单选模式有效
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public bool AllowClear { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 自动获取焦点
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public bool AutoFocus { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用键盘选择选项的时候把选中项回填到输入框中
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public bool BackFill { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 自定义输入框
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public RenderFragment CustomInput { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否默认高亮第一个选项
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public bool DefaultActiveFirstOption { get; set; } = true;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 默认的选中项
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public string DefaultValue { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否禁用
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public bool Disabled { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 输入框提示
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public string PlaceHolder { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获得焦点时的回调
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public Action<string> OnFocus { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 失去焦点时的回调
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public Action<string> OnBlur { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 选中 option,或 input 的 value 变化时,调用此函数
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public Action<string> OnChange { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 被选中时调用,参数为选中项的 value 值
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public Action<string> OnSelect { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public Func<string, string, bool> FilterOption { get; set; }
|
|
|
|
|
|
|
|
|
|
#endregion parameters
|
|
|
|
|
|
|
|
|
|
#region variable
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 浮层 数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
private IList<string> _options = new List<string>();
|
|
|
|
|
|
2020-07-31 12:43:46 +08:00
|
|
|
|
|
|
|
|
|
private bool _toggleState;
|
2020-06-27 18:24:21 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 浮层 展开/折叠状态
|
|
|
|
|
/// </summary>
|
2020-07-31 12:43:46 +08:00
|
|
|
|
private bool ToggleState
|
|
|
|
|
{
|
|
|
|
|
get => _toggleState;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_toggleState = value;
|
|
|
|
|
if (_toggleState == false) _activeOption = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-27 18:24:21 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// active 状态的 Option
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _activeOption;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 鼠标是否在 Option 上
|
|
|
|
|
/// </summary>
|
|
|
|
|
private bool _isOnOptions;
|
|
|
|
|
|
|
|
|
|
#endregion variable
|
|
|
|
|
|
|
|
|
|
#region init
|
|
|
|
|
|
|
|
|
|
protected override void OnInitialized()
|
|
|
|
|
{
|
|
|
|
|
FilterOption ??= (value, option) => option.Contains(value, StringComparison.InvariantCulture);
|
|
|
|
|
base.OnInitialized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion init
|
|
|
|
|
|
|
|
|
|
#region event
|
|
|
|
|
|
|
|
|
|
private void OnInputFocus()
|
|
|
|
|
{
|
|
|
|
|
if (Value != null || Options != null && Options.Any())
|
2020-07-31 12:43:46 +08:00
|
|
|
|
{
|
|
|
|
|
_activeOption = null;
|
2020-06-27 18:24:21 +08:00
|
|
|
|
ToggleState = true;
|
2020-07-31 12:43:46 +08:00
|
|
|
|
}
|
2020-06-27 18:24:21 +08:00
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(Value))
|
|
|
|
|
OnFocus?.Invoke(Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnInputBlur()
|
|
|
|
|
{
|
|
|
|
|
if (_isOnOptions) return;
|
|
|
|
|
|
|
|
|
|
ToggleState = false;
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(Value))
|
|
|
|
|
OnBlur?.Invoke(Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnInputChange(ChangeEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
var v = args?.Value.ToString();
|
2020-07-31 12:43:46 +08:00
|
|
|
|
CurrentValue = v;
|
2020-06-27 18:24:21 +08:00
|
|
|
|
|
|
|
|
|
if (Options != null) // Options 参数不为空时,本地过滤选项
|
|
|
|
|
{
|
|
|
|
|
_options.Clear();
|
|
|
|
|
_options = !string.IsNullOrWhiteSpace(v) ? Options.Where(option => FilterOption(v, option)).ToList() : Options.ToList();
|
|
|
|
|
|
|
|
|
|
// 默认选中第一个
|
|
|
|
|
if (_options.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
ToggleState = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (FormatList != null) // FormatList 参数不为空时,按照指定 Format 格式添加选项
|
|
|
|
|
{
|
|
|
|
|
_options.Clear();
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(v))
|
|
|
|
|
{
|
|
|
|
|
FormatList.ForEach(f => _options.Add(string.Format(f, v)));
|
|
|
|
|
}
|
|
|
|
|
// 默认选中第一个
|
|
|
|
|
if (_options.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
ToggleState = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // 一般模式,从远程获取数据添加选项
|
|
|
|
|
{
|
|
|
|
|
// 此处暂无需处理
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OnChange?.Invoke(v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnOptionMouseOver(string option)
|
|
|
|
|
{
|
|
|
|
|
_activeOption = option;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnOptionClick(string option)
|
|
|
|
|
{
|
|
|
|
|
ToggleState = false;
|
|
|
|
|
_isOnOptions = false;
|
|
|
|
|
|
|
|
|
|
if (Value != option)
|
|
|
|
|
{
|
2020-07-31 12:43:46 +08:00
|
|
|
|
CurrentValue = option;
|
2020-06-27 18:24:21 +08:00
|
|
|
|
ValueChanged.InvokeAsync(option);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OnSelect?.Invoke(option);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnOptionsMouseOver()
|
|
|
|
|
{
|
|
|
|
|
_isOnOptions = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnOptionsMouseOut()
|
|
|
|
|
{
|
|
|
|
|
_isOnOptions = false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-31 12:43:46 +08:00
|
|
|
|
public void OnKeyDown(KeyboardEventArgs args)
|
2020-06-27 18:24:21 +08:00
|
|
|
|
{
|
|
|
|
|
if (!ToggleState)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (args.Code == "NumpadEnter" || args.Code == "Enter") //Enter
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(_activeOption))
|
|
|
|
|
{
|
2020-07-31 12:43:46 +08:00
|
|
|
|
CurrentValue = _activeOption;
|
2020-07-16 13:00:23 +08:00
|
|
|
|
ValueChanged.InvokeAsync(_activeOption);
|
2020-06-27 18:24:21 +08:00
|
|
|
|
ToggleState = false;
|
2020-07-16 13:00:23 +08:00
|
|
|
|
|
2020-06-27 18:24:21 +08:00
|
|
|
|
}
|
2020-07-31 12:43:46 +08:00
|
|
|
|
else if (_options.IndexOf(Value) != -1)
|
|
|
|
|
{
|
|
|
|
|
ValueChanged.InvokeAsync(CurrentValue);
|
|
|
|
|
ToggleState = false;
|
|
|
|
|
}
|
2020-06-27 18:24:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.Code == "ArrowUp") //上键
|
|
|
|
|
{
|
2020-07-31 12:43:46 +08:00
|
|
|
|
if (_options.Count == 0) return;
|
|
|
|
|
|
2020-06-27 18:24:21 +08:00
|
|
|
|
int index = _options.IndexOf(_activeOption);
|
|
|
|
|
if (string.IsNullOrWhiteSpace(_activeOption) || index <= 0)
|
|
|
|
|
index = _options.Count;
|
|
|
|
|
|
|
|
|
|
_activeOption = _options.ElementAt(index - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.Code == "ArrowDown") //下键
|
|
|
|
|
{
|
2020-07-31 12:43:46 +08:00
|
|
|
|
if (_options.Count == 0) return;
|
|
|
|
|
|
2020-06-27 18:24:21 +08:00
|
|
|
|
int index = _options.IndexOf(_activeOption);
|
2020-07-31 12:43:46 +08:00
|
|
|
|
if (index == -1)
|
|
|
|
|
{
|
|
|
|
|
index = _options.IndexOf(Value);
|
|
|
|
|
}
|
|
|
|
|
if (index >= _options.Count - 1 || index < 0)
|
2020-06-27 18:24:21 +08:00
|
|
|
|
index = -1;
|
|
|
|
|
|
|
|
|
|
_activeOption = _options.ElementAt(index + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion event
|
|
|
|
|
|
|
|
|
|
#region public
|
|
|
|
|
|
|
|
|
|
public void LoadData(IEnumerable<string> list)
|
|
|
|
|
{
|
|
|
|
|
if (Options != null) // Options 参数不为空时,本地过滤
|
|
|
|
|
{
|
|
|
|
|
// 此处暂无需处理
|
|
|
|
|
}
|
|
|
|
|
else if (FormatList != null) // FormatList 参数不为空时,按照指定 Format 格式添加选项
|
|
|
|
|
{
|
|
|
|
|
// 此处暂无需处理
|
|
|
|
|
}
|
|
|
|
|
else // 一般模式,从远程获取数据添加选项
|
|
|
|
|
{
|
|
|
|
|
list ??= Enumerable.Empty<string>();
|
|
|
|
|
|
|
|
|
|
ToggleState = list.Any();
|
|
|
|
|
|
|
|
|
|
_options = list.ToList();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion public
|
|
|
|
|
}
|
|
|
|
|
}
|