using System; using System.Collections.Generic; using Microsoft.AspNetCore.Components; using System.Linq; using System.Collections; namespace AntDesign { public partial class Cascader : AntInputComponentBase<string> { [Parameter] public bool Readonly { get; set; } = true; /// <summary> /// 是否支持清除 /// </summary> [Parameter] public bool AllowClear { get; set; } = true; /// <summary> /// 是否显示关闭图标 /// </summary> private bool ShowClearIcon { get; set; } /// <summary> /// 当此项为 true 时,点选每级菜单选项值都会发生变化 /// </summary> [Parameter] public bool ChangeOnSelect { get; set; } /// <summary> /// 默认的选中项 /// </summary> [Parameter] public string DefaultValue { get; set; } /// <summary> /// 次级菜单的展开方式,可选 'click' 和 'hover' /// </summary> [Parameter] public string ExpandTrigger { get; set; } /// <summary> /// 当下拉列表为空时显示的内容 /// </summary> [Parameter] public string NotFoundContent { get; set; } = "Not Found"; /// <summary> /// 输入框占位文本 /// </summary> [Parameter] public string PlaceHolder { get; set; } = "请选择"; [Parameter] public string PopupContainerSelector { get; set; } = "body"; /// <summary> /// 在选择框中显示搜索框 /// </summary> [Parameter] public bool ShowSearch { get; set; } /// <summary> /// 选择完成后的回调(参数为选中的节点集合及选中值) /// </summary> [Parameter] public Action<List<CascaderNode>, string, string> OnChange { get; set; } [Parameter] public IReadOnlyCollection<CascaderNode> Options { get { if (_nodelist != null) return _nodelist; return Array.Empty<CascaderNode>(); } set { if (value == null || value.Count == 0) { _nodelist = null; return; } if (_nodelist == null) _nodelist = new List<CascaderNode>(); else if (_nodelist.Count != 0) _nodelist.Clear(); _nodelist.AddRange(value); ProcessParentAndDefault(); } } private List<CascaderNode> _nodelist; /// <summary> /// 选中节点集合(click) /// </summary> internal List<CascaderNode> _selectedNodes = new List<CascaderNode>(); /// <summary> /// 选中节点集合(hover) /// </summary> internal List<CascaderNode> _hoverSelectedNodes = new List<CascaderNode>(); /// <summary> /// 用于渲染下拉节点集合(一级节点除外) /// </summary> internal List<CascaderNode> _renderNodes = new List<CascaderNode>(); /// <summary> /// 浮层 展开/折叠状态 /// </summary> private bool ToggleState { get; set; } /// <summary> /// 鼠标是否处于 浮层 之上 /// </summary> private bool IsOnCascader { get; set; } /// <summary> /// 选择节点类型 /// Click: 点击选中节点, Hover: 鼠标移入选中节点 /// </summary> private SelectedTypeEnum SelectedType { get; set; } private ClassMapper _inputClassMapper = new ClassMapper(); private string _displayText; private static Hashtable _sizeMap = new Hashtable() { ["large"] = "lg", ["small"] = "sm" }; protected override void OnInitialized() { base.OnInitialized(); ClassMapper.Add("ant-cascader-picker") .GetIf(() => $"ant-cascader-picker-{Size}", () => _sizeMap.ContainsKey(Size)) .GetIf(() => $"ant-input-{_sizeMap[Size]}", () => _sizeMap.ContainsKey(Size)) ; _inputClassMapper .Add("ant-input") .Add("ant-cascader-input") .GetIf(() => $"ant-input-{_sizeMap[Size]}", () => _sizeMap.ContainsKey(Size)); } protected override void OnValueChange(string value) { base.OnValueChange(value); RefreshNodeValue(value); } #region event /// <summary> /// 输入框单击(显示/隐藏浮层) /// </summary> private void InputOnToggle() { SelectedType = SelectedTypeEnum.Click; _hoverSelectedNodes.Clear(); ToggleState = !ToggleState; } /// <summary> /// 输入框/浮层失去焦点(隐藏浮层) /// </summary> private void CascaderOnBlur() { if (!IsOnCascader) { ToggleState = false; _renderNodes = _selectedNodes; } } /// <summary> /// 输入框鼠标移入 /// </summary> private void InputOnMouseOver() { if (!AllowClear) return; ShowClearIcon = true; } /// <summary> /// 输入框鼠标移出 /// </summary> private void InputOnMouseOut() { if (!AllowClear) return; ShowClearIcon = false; } /// <summary> /// 清除已选择项 /// </summary> private void ClearSelected() { _selectedNodes.Clear(); _hoverSelectedNodes.Clear(); _displayText = string.Empty; CurrentValueAsString = string.Empty; } /// <summary> /// 浮层移入 /// </summary> private void NodesOnMouseOver() { if (!AllowClear) return; IsOnCascader = true; } /// <summary> /// 浮层移出 /// </summary> private void NodesOnMouseOut() { if (!AllowClear) return; IsOnCascader = false; } /// <summary> /// 下拉节点单击 /// </summary> /// <param name="node"></param> private void NodeOnClick(CascaderNode node) { if (node.Disabled) return; SetSelectedNode(node, SelectedTypeEnum.Click); } /// <summary> /// 下拉节点移入 /// </summary> /// <param name="node"></param> private void NodeOnMouseOver(CascaderNode node) { if (ExpandTrigger != "hover") return; if (node.Disabled) return; if (!node.HasChildren) return; SetSelectedNode(node, SelectedTypeEnum.Hover); } #endregion event /// <summary> /// 选中节点 /// </summary> /// <param name="cascaderNode"></param> /// <param name="selectedType"></param> internal void SetSelectedNode(CascaderNode cascaderNode, SelectedTypeEnum selectedType) { if (cascaderNode == null) return; SelectedType = selectedType; if (selectedType == SelectedTypeEnum.Click) { _selectedNodes.Clear(); SetSelectedNodeWithParent(cascaderNode, ref _selectedNodes); _renderNodes = _selectedNodes; if (ChangeOnSelect || !cascaderNode.HasChildren) SetValue(cascaderNode.Value); } else { _hoverSelectedNodes.Clear(); SetSelectedNodeWithParent(cascaderNode, ref _hoverSelectedNodes); _renderNodes = _hoverSelectedNodes; } _renderNodes.Sort((x, y) => x.Level.CompareTo(y.Level)); //Level 升序排序 if (!cascaderNode.HasChildren) { ToggleState = false; IsOnCascader = false; } } /// <summary> /// 设置选中所有父节点 /// </summary> /// <param name="node"></param> /// <param name="list"></param> private void SetSelectedNodeWithParent(CascaderNode node, ref List<CascaderNode> list) { if (node == null) return; list.Add(node); SetSelectedNodeWithParent(node.ParentNode, ref list); } /// <summary> /// Options 更新后处理父节点和默认值 /// </summary> private void ProcessParentAndDefault() { InitCascaderNodeState(_nodelist, null, 0); SetDefaultValue(Value ?? DefaultValue); } /// <summary> /// 初始化节点属性(Level, ParentNode) /// </summary> /// <param name="list"></param> /// <param name="parentNode"></param> /// <param name="level"></param> private void InitCascaderNodeState(List<CascaderNode> list, CascaderNode parentNode, int level) { if (list == null) return; foreach (var node in list) { node.Level = level; node.ParentNode = parentNode; if (node.HasChildren) InitCascaderNodeState(node.Children.ToList(), node, level + 1); } } /// <summary> /// 刷新选中的内容 /// </summary> /// <param name="value"></param> private void RefreshNodeValue(string value) { _selectedNodes.Clear(); var node = GetNodeByValue(_nodelist, value); SetSelectedNodeWithParent(node, ref _selectedNodes); _renderNodes = _selectedNodes; RefreshDisplayValue(); OnChange?.Invoke(_selectedNodes, value, _displayText); } /// <summary> /// 设置默认选中 /// </summary> /// <param name="defaultValue"></param> private void SetDefaultValue(string defaultValue) { if (string.IsNullOrWhiteSpace(defaultValue)) return; _selectedNodes.Clear(); var node = GetNodeByValue(_nodelist, defaultValue); SetSelectedNodeWithParent(node, ref _selectedNodes); _renderNodes = _selectedNodes; SetValue(node?.Value); } /// <summary> /// 设置输入框选中值 /// </summary> /// <param name="value"></param> private void SetValue(string value) { RefreshDisplayValue(); if (Value != value) { CurrentValueAsString = value; } } private void RefreshDisplayValue() { _selectedNodes.Sort((x, y) => x.Level.CompareTo(y.Level)); //Level 升序排序 _displayText = string.Empty; int count = 0; foreach (var node in _selectedNodes) { if (node == null) continue; if (count < _selectedNodes.Count - 1) _displayText += node.Label + " / "; else _displayText += node.Label; count++; } } /// <summary> /// 根据指定值获取节点 /// </summary> /// <param name="list"></param> /// <param name="value"></param> /// <returns></returns> private CascaderNode GetNodeByValue(List<CascaderNode> list, string value) { if (list == null) return null; CascaderNode result = null; foreach (var node in list) { if (node.Value == value) return node; if (node.HasChildren) { var nd = GetNodeByValue(node.Children.ToList(), value); if (nd != null) result = nd; } } return result; } } }