Enterprise-level component library based on Bootstrap and Blazor

star nuget license download repo commit master coverage

Tree 树形控件

用清晰的层级结构展示信息,可展开或折叠

基础的树形结构展示

Demo

通过设置 OnTreeItemClick 属性监控树形控件节点被点击时的事件,点击树形控件节点时下面日志显示选中节点的数据

  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

适用于需要选择层级时使用

Demo

通过设置 OnTreeItemChecked 属性监控树形控件节点被勾选时的事件,选中树形控件节点前复选框时下面日志显示选中节点的数据

  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

可将 Tree 的某些节点设置为禁用状态

Demo

通过设置数据源 TreeItem 对象的 Disabled 属性,来控制此节点是否可以进行勾选动作,设置为 false 时不影响节点展开/收缩功能

  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

对于同一级的节点,每次只能展开一个

Demo

通过设置 Tree 组件的 IsAccordion 属性开启手风琴效果

  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

可将 Tree 的某些节点设置为默认展开或默认选中

Demo

通过设置 TreeItem 对象的 IsExpanded 属性,来控制此节点是否默认为展开状态,本例中 导航二子菜单二 默认为展开状态,其余节点默认为收缩状态

  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

通过设置 ShowIcon 来控制组件是否显示图标

Demo

通过设置 TreeItem 对象的 ShowIcon 属性,来控制此节点是否显示图标

  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

通过设置 ClickToggleNode 来控制点击节点时是否进行展开收缩操作

Demo

通过设置 TreeItem 对象的 ClickToggleNode 属性,来控制此节点是否通过点击来实现展开收缩操作

  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

Tree 组件内部可开启 Checkbox 内置到验证表单时会显示 DisplayName 此功能在树状组件内需要禁止

Demo

通过设置 ShowCheckbox 属性显示 Checkbox 内置到验证组件 ValidateForm 中不显示 DisplayName

  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

展开节点时动态添加子节点

Demo

通过设置节点 HasChildNode 控制是否显示节点小箭头图片 。通过Tree的 OnExpandNode 委托添加节点

  • 导航一
  • 导航二
    • 子菜单一
    • 懒加载
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 懒加载延时
  • 导航三

通过设置 TreeItem Template 来实现自己的节点模板

Demo
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

通过设置 TreeItem CssClass 来实现自己的节点样式

Demo
  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

通过设置 OnTreeItemChecked 回调委托获取所有节点

Demo
  • 导航一
  • 导航二
    • 子菜单一
    • 子菜单二
      • 孙菜单一
      • 孙菜单二
        • 曾孙菜单一
          • 曾曾孙菜单一
          • 曾曾孙菜单二
          • 曾曾孙菜单三
        • 曾孙菜单二
        • 曾孙菜单三
      • 孙菜单三
    • 子菜单三
  • 导航三

Attributes

Loading...

TreeItem 属性

Loading...
@page "/trees"

<h3>Tree 树形控件</h3>

<h4>用清晰的层级结构展示信息,可展开或折叠</h4>

<DemoBlock Title="基础用法" Introduction="基础的树形结构展示" Name="Normal">
    <p>
        通过设置 <code>OnTreeItemClick</code> 属性监控树形控件节点被点击时的事件,点击树形控件节点时下面日志显示选中节点的数据
    </p>
    <Tree Items="@Items" OnTreeItemClick="@OnTreeItemClick" />
    <BlockLogger @ref="Trace" class="mt-3" />
</DemoBlock>

<DemoBlock Title="可选择" Introduction="适用于需要选择层级时使用" Name="Optional">
    <p>
        通过设置 <code>OnTreeItemChecked</code> 属性监控树形控件节点被勾选时的事件,选中树形控件节点前复选框时下面日志显示选中节点的数据
    </p>
    <Tree Items="@CheckedItems" ShowCheckbox="true" OnTreeItemChecked="@OnTreeItemChecked" />
    <BlockLogger @ref="TraceChecked" class="mt-3" />
</DemoBlock>

<DemoBlock Title="禁用状态" Introduction="可将 Tree 的某些节点设置为禁用状态" Name="TreeDisable">
    <p>
        通过设置数据源 <code>TreeItem</code> 对象的 <code>Disabled</code> 属性,来控制此节点是否可以进行勾选动作,设置为 <code>false</code> 时不影响节点展开/收缩功能
    </p>
    <Tree Items="@DisabledItems" ShowCheckbox="true" />
</DemoBlock>

<DemoBlock Title="手风琴模式" Introduction="对于同一级的节点,每次只能展开一个" Name="AccordionModel">
    <p>通过设置 <code>Tree</code> 组件的 <code>IsAccordion</code> 属性开启手风琴效果</p>
    <Tree Items="@Items" ShowCheckbox="true" IsAccordion="true" />
</DemoBlock>

<DemoBlock Title="默认展开和默认选中" Introduction="可将 <code>Tree</code> 的某些节点设置为默认展开或默认选中" Name="DefauleExpand">
    <p>
        通过设置 <code>TreeItem</code> 对象的 <code>IsExpanded</code> 属性,来控制此节点是否默认为展开状态,本例中 <b>导航二</b> 与 <b>子菜单二</b> 默认为展开状态,其余节点默认为收缩状态
    </p>
    <Tree Items="@CheckedItems" ShowCheckbox="true" />
</DemoBlock>

<DemoBlock Title="显示图标" Introduction="通过设置 <code>ShowIcon</code> 来控制组件是否显示图标" Name="TreeDisplayIcon">
    <p>
        通过设置 <code>TreeItem</code> 对象的 <code>ShowIcon</code> 属性,来控制此节点是否显示图标
    </p>
    <Tree Items="@GetIconItems()" ShowIcon="true" ShowCheckbox="true" />
</DemoBlock>

<DemoBlock Title="点击节点展开收缩功能" Introduction="通过设置 <code>ClickToggleNode</code> 来控制点击节点时是否进行展开收缩操作" Name="TreeClickExpand">
    <p>
        通过设置 <code>TreeItem</code> 对象的 <code>ClickToggleNode</code> 属性,来控制此节点是否通过点击来实现展开收缩操作
    </p>
    <Tree Items="@Items" ShowIcon="true" ShowCheckbox="true" ClickToggleNode="true" />
</DemoBlock>

<DemoBlock Title="Tree 组件内置到验证表单中" Introduction="<code>Tree</code> 组件内部可开启 <code>Checkbox</code> 内置到验证表单时会显示 <code>DisplayName</code> 此功能在树状组件内需要禁止" Name="TreeValidationForm">
    <p>
        通过设置 <code>ShowCheckbox</code> 属性显示 <code>Checkbox</code> 内置到验证组件 <code>ValidateForm</code> 中不显示 <code>DisplayName</code>
    </p>
    <ValidateForm Model="@Model">
        <Tree Items="@Items" OnTreeItemClick="@OnTreeItemClick" ShowCheckbox="true" />
    </ValidateForm>
</DemoBlock>

<DemoBlock Title="懒加载" Introduction="展开节点时动态添加子节点" Name="TreeLazyLoading">
    <p>
        通过设置节点 <code>HasChildNode</code> 控制是否显示节点小箭头图片 。通过Tree的 <code>OnExpandNode</code> 委托添加节点
    </p>
    <Tree ClickToggleNode="true" Items="@GetLazyItems()" OnExpandNode="OnExpandNode" />
</DemoBlock>

<DemoBlock Title="自定义节点" Introduction="通过设置 <code>TreeItem</code> <code>Template</code> 来实现自己的节点模板" Name="TreeCustomNode">
    <Tree ClickToggleNode="true" Items="GetTemplateItems()" />
</DemoBlock>

<DemoBlock Title="节点颜色" Introduction="通过设置 <code>TreeItem</code> <code>CssClass</code> 来实现自己的节点样式" Name="TreeNodeColor">
    <Tree ClickToggleNode="true" Items="GetColorItems()" />
</DemoBlock>

<DemoBlock Title="获取所有选中节点" Introduction="通过设置 <code>OnTreeItemChecked</code> 回调委托获取所有节点" Name="CheckedItems">
    <Tree ShowCheckbox="true" Items="@Items" OnTreeItemChecked="@OnTreeItemChecked" />
    <BlockLogger @ref="TraceCheckedItems" class="mt-3" />
</DemoBlock>

<AttributeTable Items="@GetAttributes()" />

<AttributeTable Items="@GetTreeItemAttributes()" Title="TreeItem 属性" />
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.Localization;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;

namespace BootstrapBlazor.Shared.Samples;

/// <summary>
/// 
/// </summary>
public sealed partial class Trees
{
    [NotNull]
    private BlockLogger? Trace { get; set; }

    [NotNull]
    private BlockLogger? TraceChecked { get; set; }

    [NotNull]
    private BlockLogger? TraceCheckedItems { get; set; }

    [Inject]
    [NotNull]
    private IStringLocalizer<Foo>? Localizer { get; set; }

    private Foo Model => Foo.Generate(Localizer);

    private List<TreeItem> Items { get; set; } = TreeDataFoo.GetTreeItems();

    private List<TreeItem> CheckedItems { get; set; } = GetCheckedItems();

    private static List<TreeItem> GetCheckedItems()
    {
        var ret = TreeDataFoo.GetTreeItems();
        ret[1].Items[1].Checked = true;
        return ret;
    }

    private List<TreeItem> DisabledItems { get; set; } = GetDisabledItems();

    private static List<TreeItem> GetDisabledItems()
    {
        var ret = TreeDataFoo.GetTreeItems();
        ret[1].Items[1].IsDisabled = true;
        return ret;
    }

    private static List<TreeItem> GetIconItems()
    {
        var ret = TreeDataFoo.GetTreeItems();
        ret[1].Items[0].Icon = "fa fa-fa";
        ret[1].Items[1].Icon = "fa fa-fa";
        ret[1].Items[2].Icon = "fa fa-fa";
        return ret;
    }

    private static List<TreeItem> GetLazyItems()
    {
        var ret = TreeDataFoo.GetTreeItems();
        ret[1].Items[0].IsExpanded = true;
        ret[1].Items[1].Text = "懒加载";
        ret[1].Items[1].HasChildNode = true;
        ret[1].Items[2].Text = "懒加载延时";
        ret[1].Items[2].HasChildNode = true;
        ret[1].Items[2].Key = "Delay";

        return ret;
    }

    private static List<TreeItem> GetTemplateItems()
    {
        var ret = TreeDataFoo.GetTreeItems();
        ret[0].Template = BootstrapDynamicComponent.CreateComponent<CustomerTreeItem>().Render();
        return ret;
    }

    private static List<TreeItem> GetColorItems()
    {
        var ret = TreeDataFoo.GetTreeItems();
        ret[0].CssClass = "text-primary";
        ret[1].CssClass = "text-success";
        ret[2].CssClass = "text-danger";
        return ret;
    }

    private class CustomerTreeItem : ComponentBase
    {
        [Inject]
        [NotNull]
        private ToastService? ToastService { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="builder"></param>
        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.OpenComponent<Button>(0);
            builder.AddAttribute(1, nameof(Button.Icon), "fa fa-fa");
            builder.AddAttribute(2, nameof(Button.Text), "Click");
            builder.AddAttribute(3, nameof(Button.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, e =>
            {
                ToastService.Warning("自定义 TreeItem", "测试 TreeItem 按钮点击事件");
            }));
            builder.CloseComponent();
        }
    }

    private Task OnTreeItemClick(TreeItem item)
    {
        Trace.Log($"TreeItem: {item.Text} clicked");
        return Task.CompletedTask;
    }

    private Task OnTreeItemChecked(TreeItem item)
    {
        var state = item.Checked ? "选中" : "未选中";
        TraceChecked.Log($"TreeItem: {item.Text} {state}");
        return Task.CompletedTask;
    }

    private static async Task OnExpandNode(TreeItem item)
    {
        if (!item.Items.Any() && item.HasChildNode && !item.ShowLoading)
        {
            item.ShowLoading = true;
            if (item.Key?.ToString() == "Delay")
            {
                await Task.Delay(800);
            }
            item.Items.AddRange(new TreeItem[]
            {
                    new TreeItem()
                    {
                        Text = "懒加载子节点1",
                        HasChildNode = true
                    },
                    new TreeItem() { Text = "懒加载子节点2" }
            });
            item.ShowLoading = false;
        }
    }

    private Task OnTreeItemChecked(List<TreeItem> items)
    {
        TraceCheckedItems.Log($"当前共选中{items.Count}项");
        return Task.CompletedTask;
    }

    /// <summary>
    /// 获得属性方法
    /// </summary>
    /// <returns></returns>
    private static IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
    {
            // TODO: 移动到数据库中
            new AttributeItem() {
                Name = "Items",
                Description = "菜单数据集合",
                Type = "IEnumerable<TreeItem>",
                ValueList = " — ",
                DefaultValue = "new List<TreeItem>(20)"
            },
            new AttributeItem() {
                Name = "ClickToggleNode",
                Description = "是否点击节点时展开或者收缩子项",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "ShowCheckbox",
                Description = "是否显示 CheckBox",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "ShowIcon",
                Description = "是否显示 Icon",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "ShowSkeleton",
                Description = "是否显示加载骨架屏",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "OnTreeItemClick",
                Description = "树形控件节点点击时回调委托",
                Type = "Func<TreeItem, Task>",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "OnTreeItemChecked",
                Description = "树形控件节点选中时回调委托",
                Type = "Func<TreeItem, Task>",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "OnExpandNode",
                Description = "树形控件节点展开回调委托",
                Type = "Func<TreeItem, Task>",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "OnCheckedItems",
                Description = "树形控件获取所有选中节点回调委托",
                Type = "Func<List<TreeItem>, Task>",
                ValueList = " — ",
                DefaultValue = " — "
            }
    };

    private static IEnumerable<AttributeItem> GetTreeItemAttributes() => new AttributeItem[]
    {
            // TODO: 移动到数据库中
            new AttributeItem() {
                Name = nameof(TreeItem.Key),
                Description = "TreeItem 标识",
                Type = "object?",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "Items",
                Description = "子节点数据源",
                Type = "IEnumerable<TreeItem>",
                ValueList = " — ",
                DefaultValue = "new List<TreeItem>(20)"
            },
            new AttributeItem() {
                Name = "Text",
                Description = "显示文字",
                Type = "string",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "Icon",
                Description = "显示图标",
                Type = "string",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "CssClass",
                Description = "节点自定义样式",
                Type = "string",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "Checked",
                Description = "是否被选中",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = nameof(TreeItem.IsDisabled),
                Description = "是否被禁用",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "IsExpanded",
                Description = "是否展开",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = nameof(TreeItem.Tag),
                Description = "TreeItem 附加数据",
                Type = "object?",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = nameof(TreeItem.HasChildNode),
                Description = "是否有子节点",
                Type = "bool",
                ValueList = " true|false ",
                DefaultValue = " false "
            },
            new AttributeItem() {
                Name = nameof(TreeItem.ShowLoading),
                Description = "是否显示子节点加载动画",
                Type = "bool",
                ValueList = " true|false ",
                DefaultValue = " false "
            },
            new AttributeItem()
            {
                Name = nameof(TreeItem.Template),
                Description = "子节点模板",
                Type = nameof(RenderFragment),
                ValueList = " — ",
                DefaultValue = " — "
            }
    };
}

B 站相关视频链接

暂无

交流群

QQ Group:BootstrapAdmin & Blazor 795206915 675147445 Welcome to join the group discussion
Themes
Bootstrap
Motronic
Ant Design (完善中)
LayUI (完善中)
An error has occurred. This application may no longer respond until reloaded. Reload