65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Blazor 中构建文件夹树

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (7投票s)

2022 年 2 月 10 日

CPOL

2分钟阅读

viewsIcon

16713

前端和后端文件夹树的实现

引言

由于 Blazor 是一种相对较新的技术,可能很难找到其他框架中常见的特性。这就是递归文件夹树的情况,我只能找到“将我的包添加到你的项目”的解决方案。本文的目的是分享该解决方案的前端和后端,以及构建文件夹树所需的全部代码。

从后端开始

首先,我使用了一个名为“Group”的类,它将是“Folder”(如果你愿意,可以将其命名为“Folder”)。这是一个简单且常见的类。唯一值得注意的区别是,它有一个“ParentGroupId”整数属性,用于引用自身(是的,一个组中包含一个组!),这对于创建我们需要的“文件夹中包含文件夹”效果非常重要。

public class Group
{
    public string Name { get; set; }
    public string? Description { get; set; }
    public int? ParentGroupId { get; set; }

    public Group ParentGroup { get; set; }
    public virtual List<Group> SubGroups { get; set; }
}

你可以将其存储在 SQL Server、MySQL 或任何其他数据库中。我不会介绍如何使用 SQL Server 或创建表。我假设你已经可以将该类保存到表中并检索信息。

递归方法以获取所有文件夹/组信息

在你的存储库/控制器/或其他你正在使用的组件中,你需要创建一个方法来递归地获取所有组/文件夹信息。在我的例子中,我使用了我公司的一个名为 Sparc 的框架,它完成了所有这些神奇的操作。最后,我会发布一个链接,你可以在那里获取更多信息。这个方法将无限地包含组中的组(无论有多少组)。你可以在下面找到代码。

public async Task<List<Group> GetGroups()
{
    // Get all groups from DB to save all the extra database calls
    var allGroups = await GroupRepository
        .Query
        .ToListAsync();

    // Start recursive function with the top of the tree
    LoadSubgroups(allGroups, null);

    allGroups = allGroups.Where(x => x.ParentGroupId == null).ToList();
    
    return allGroups;
}

private List<Group> LoadSubgroups(List<Group> allGroups, Group? parentGroup)
{
    var groups = allGroups.Where(x => x.ParentGroupId == parentGroup?.Id).ToList();

    foreach (var group in groups)
        group.SubGroups = LoadSubgroups(allGroups, group);

    return groups;
}

你可以注意到,GetGroups() 方法调用了 LoadSubgroups() 方法,而 LoadSubgroups() 方法又调用了自身!其思想是 LoadSubgroups() 方法递归地调用自身,直到没有组需要加载为止。

使用组件处理前端

我们将面临与后端相同的挑战:递归性!在这种情况下,我们需要使用 Blazor 组件来创建递归效果,为每个将要显示的新组/文件夹创建新的 HTML 元素。我假设你已经可以从 API 获取组/文件夹信息。

GroupTree 组件

首先,我们需要创建 GroupTree/FolderTree 组件

<div class="folder-tree-wrapper">
    <ul class="folder-tree">
        @foreach (var group in Groups)
        {
            <GroupItem Group="group" />
        }
    </ul>
</div>

@code {
    [Parameter] public List<GetGroupsResponse> Groups { get; set; }
}

你可以注意到,有一个未定义的 HTML 元素:<GroupItem /> 元素!这将是另一个组件(子组件),它将实际包含组。

GroupItem 组件

<li>
    <div class="item-container">
        @if (Group.SubGroups.Any())
            {
                @if (Group.IsExpanded)
                {
                    <i class="material-icons expand-more" 
                     style="transform: rotate(180deg)" 
                     @onclick="ToggleGroup">expand_less</i>
                }
                else
                {
                    <i class="material-icons expand-more" 
                     style="transform: rotate(90deg)" 
                     @onclick="ToggleGroup">expand_less</i>
                }
            }
        <i class="material-icons" style="cursor: pointer; 
                 @(Group.SubGroups.Any() ? "" : "padding-left: 18px")">
                 @(allEntriesSelected ? "check_box" : "check_box_outline_blank")</i>
        <div style="display: inline-block" @onclick="ToggleGroup">
            <i class="material-icons">folder</i>
            <div style="display: inline-block">@Group.Name</div>
        </div>
    </div>

    @if (Group.SubGroups.Any() && Group.IsExpanded)
    {
        <ul>
        @foreach (var subGroup in Group.SubGroups)
        {
            <GroupItem Group="subGroup"/>
        }
        </ul>
    }
</li>

@code {
    [Parameter] public GetGroupsResponse Group { get; set; }
    public bool allEntriesSelected { get; set; }

    async Task ToggleGroup()
    {
        Group.IsExpanded = !Group.IsExpanded;
    }
}

就这样!这就是使用 Blazor 创建文件夹/树解决方案所需的一切。现在你只需要在想要使用它的页面上调用 GroupTree 组件,如下所示

<GroupTree Groups="groups" />

如果你有任何问题或想了解更多关于我提到的 Sparc 解决方案的信息,请给我留言!无论如何,我都可以帮助你。:)

历史

  • 2022 年 2 月 10 日:初始版本
© . All rights reserved.