Skip to content

Commit cdb4053

Browse files
committed
优化TreeView组件 虚拟滚动性能,更换List为HashSet,降低时间复杂度
1 parent 9a09c24 commit cdb4053

File tree

2 files changed

+47
-27
lines changed

2 files changed

+47
-27
lines changed

src/BootstrapBlazor/Misc/ExpandableNodeCache.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,32 @@ namespace BootstrapBlazor.Components;
1313
/// <remarks>
1414
/// 构造函数
1515
/// </remarks>
16-
public class ExpandableNodeCache<TNode, TItem>(Func<TItem, TItem, bool> comparer) where TNode : IExpandableNode<TItem>
16+
public class ExpandableNodeCache<TNode, TItem> where TNode : IExpandableNode<TItem>
1717
{
1818
/// <summary>
1919
/// 所有已展开行集合 作为缓存使用
2020
/// </summary>
21-
protected List<TItem> ExpandedNodeCache { get; } = new(50);
21+
protected HashSet<TItem> ExpandedNodeCache { get; }
2222

2323
/// <summary>
2424
/// 所有已收缩行集合 作为缓存使用
2525
/// </summary>
26-
protected List<TItem> CollapsedNodeCache { get; } = new(50);
26+
protected HashSet<TItem> CollapsedNodeCache { get; }
2727

2828
/// <summary>
2929
/// 对象比较器
3030
/// </summary>
31-
protected IEqualityComparer<TItem> EqualityComparer { get; } = new ModelComparer<TItem>(comparer);
31+
protected IEqualityComparer<TItem> EqualityComparer { get; }
3232

33+
/// <remarks>
34+
/// 构造函数
35+
/// </remarks>
36+
public ExpandableNodeCache(Func<TItem, TItem, bool> comparer)
37+
{
38+
EqualityComparer = new ModelComparer<TItem>(comparer);
39+
ExpandedNodeCache = new(50, EqualityComparer);
40+
CollapsedNodeCache = new(50, EqualityComparer);
41+
}
3342
/// <summary>
3443
/// 节点展开收缩状态切换方法
3544
/// </summary>
@@ -42,13 +51,13 @@ public virtual async Task ToggleNodeAsync(TNode node, Func<TNode, Task<IEnumerab
4251
if (node.IsExpand)
4352
{
4453
// 展开节点缓存增加此节点
45-
if (!ExpandedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
54+
if (!ExpandedNodeCache.Contains(node.Value))
4655
{
4756
ExpandedNodeCache.Add(node.Value);
4857
}
4958

5059
// 收缩节点缓存移除此节点
51-
CollapsedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
60+
CollapsedNodeCache.Remove(node.Value);
5261

5362
// 无子项时通过回调方法延时加载
5463
if (!node.Items.Any())
@@ -64,10 +73,10 @@ public virtual async Task ToggleNodeAsync(TNode node, Func<TNode, Task<IEnumerab
6473
else
6574
{
6675
// 展开节点缓存移除此节点
67-
ExpandedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
76+
ExpandedNodeCache.Remove(node.Value);
6877

6978
// 收缩节点缓存添加此节点
70-
if (!CollapsedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
79+
if (!CollapsedNodeCache.Contains(node.Value))
7180
{
7281
CollapsedNodeCache.Add(node.Value);
7382
}
@@ -98,7 +107,7 @@ public async Task CheckExpandAsync(TNode node, Func<TNode, Task<IEnumerable<IExp
98107
else
99108
{
100109
var needRemove = true;
101-
if (ExpandedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
110+
if (ExpandedNodeCache.Contains(node.Value))
102111
{
103112
// 原来是展开状态,
104113
if (node.HasChildren)
@@ -119,7 +128,7 @@ public async Task CheckExpandAsync(TNode node, Func<TNode, Task<IEnumerable<IExp
119128
}
120129
if (needRemove)
121130
{
122-
ExpandedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
131+
ExpandedNodeCache.Remove(node.Value);
123132
}
124133
}
125134
}

src/BootstrapBlazor/Misc/TreeNodeCache.cs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,40 @@
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
55

6+
67
namespace BootstrapBlazor.Components;
78

89
/// <summary>
910
/// Tree 组件节点缓存类
1011
/// </summary>
1112
/// <typeparam name="TNode"></typeparam>
1213
/// <typeparam name="TItem"></typeparam>
13-
public class TreeNodeCache<TNode, TItem>(Func<TItem, TItem, bool> comparer) : ExpandableNodeCache<TNode, TItem>(comparer) where TNode : ICheckableNode<TItem>
14+
public class TreeNodeCache<TNode, TItem> : ExpandableNodeCache<TNode, TItem> where TNode : ICheckableNode<TItem>
1415
{
16+
/// <remarks>
17+
/// 构造函数
18+
/// </remarks>
19+
public TreeNodeCache(Func<TItem, TItem, bool> comparer) : base(comparer)
20+
{
21+
CheckedNodeCache = new(50, EqualityComparer);
22+
UncheckedNodeCache = new(50, EqualityComparer);
23+
IndeterminateNodeCache = new(50, EqualityComparer);
24+
}
25+
1526
/// <summary>
1627
/// 获得 所有选中节点集合 作为缓存使用
1728
/// </summary>
18-
protected List<TItem> CheckedNodeCache { get; } = new(50);
29+
protected HashSet<TItem> CheckedNodeCache { get; }
1930

2031
/// <summary>
2132
/// 获得 所有未选中节点集合 作为缓存使用
2233
/// </summary>
23-
protected List<TItem> UncheckedNodeCache { get; } = new(50);
34+
protected HashSet<TItem> UncheckedNodeCache { get; }
2435

2536
/// <summary>
2637
/// 获得 所有未选中节点集合 作为缓存使用
2738
/// </summary>
28-
protected List<TItem> IndeterminateNodeCache { get; } = new(50);
39+
protected HashSet<TItem> IndeterminateNodeCache { get; }
2940

3041
/// <summary>
3142
/// 切换选中状态方法
@@ -37,35 +48,35 @@ public virtual void ToggleCheck(TNode node)
3748
if (node.CheckedState == CheckboxState.Checked)
3849
{
3950
// 未选中节点缓存移除此节点
40-
UncheckedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
41-
IndeterminateNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
51+
UncheckedNodeCache.Remove(node.Value);
52+
IndeterminateNodeCache.Remove(node.Value);
4253

4354
// 选中节点缓存添加此节点
44-
if (!CheckedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
55+
if (!CheckedNodeCache.Contains(node.Value))
4556
{
4657
CheckedNodeCache.Add(node.Value);
4758
}
4859
}
4960
else if (node.CheckedState == CheckboxState.UnChecked)
5061
{
5162
// 选中节点缓存添加此节点
52-
CheckedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
53-
IndeterminateNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
63+
CheckedNodeCache.Remove(node.Value);
64+
IndeterminateNodeCache.Remove(node.Value);
5465

5566
// 未选中节点缓存移除此节点
56-
if (!UncheckedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
67+
if (!UncheckedNodeCache.Contains(node.Value))
5768
{
5869
UncheckedNodeCache.Add(node.Value);
5970
}
6071
}
6172
else
6273
{
6374
// 不确定节点缓存添加此节点
64-
CheckedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
65-
UncheckedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
75+
CheckedNodeCache.Remove(node.Value);
76+
UncheckedNodeCache.Remove(node.Value);
6677

6778
// 未选中节点缓存移除此节点
68-
if (!IndeterminateNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
79+
if (!IndeterminateNodeCache.Contains(node.Value))
6980
{
7081
IndeterminateNodeCache.Add(node.Value);
7182
}
@@ -81,7 +92,7 @@ private void IsChecked(TNode node)
8192
{
8293
// 当前节点状态为未确定状态
8394
var nodes = node.Items.OfType<ICheckableNode<TItem>>();
84-
if (CheckedNodeCache.Any(i => EqualityComparer.Equals(i, node.Value)))
95+
if (CheckedNodeCache.Contains(node.Value))
8596
{
8697
node.CheckedState = CheckboxState.Checked;
8798
}
@@ -99,9 +110,9 @@ void CheckChildren(IEnumerable<ICheckableNode<TItem>> nodes)
99110
{
100111
if (nodes.Any())
101112
{
102-
CheckedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
103-
UncheckedNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
104-
IndeterminateNodeCache.RemoveAll(i => EqualityComparer.Equals(i, node.Value));
113+
CheckedNodeCache.Remove(node.Value);
114+
UncheckedNodeCache.Remove(node.Value);
115+
IndeterminateNodeCache.Remove(node.Value);
105116

106117
// 查看子节点状态
107118
if (nodes.All(i => i.CheckedState == CheckboxState.Checked))

0 commit comments

Comments
 (0)