Enterprise-level component library based on Bootstrap and Blazor
gitee
version
license
download
repo
commit
build
coverage

Table 表格

常用于单表维护,通过属性配置实现简单的增、删、改、查、排序、过滤、搜索等常用功能,通过 Template 的高级用法能实现非常复杂的业务需求功能

设置 ShowSearch 显示查询组件

Demo

本例中设置 Count 右侧对齐,Complete 列设置为居中对齐,布尔类型列自动渲染成 Switch 组件

当设置了 OnAddAsync 或者 OnSaveAsync 回调委托方法时,如果未设置 EditTemplate 编辑模板时,组件会尝试自动生成表单维护 UI

Demo

通过设置 TItem 泛型约束的类实例 Foo 属性的 [Required] 等验证标签即可实现客户端验证

数据绑定类型为可为空类型时自动允许为空,如日期绑定列为 DateTime? 类型

数据绑定类型为数值类型时如,如数量绑定列为 int 类型,自动进行数值验证

表格呈现的有些数据列是计算得到的结果,此种类型的列是无法参与编辑的,通过设置 Editable=false 自动生成编辑 UI 时就不会生成此列编辑组件,如本示例中 Count 列在编辑弹窗中是不出现的

通过设置 Readonly=true 自动生成编辑 UI 会将此字段进行只读处理,新建时请对 Model 进行默认值赋值

通过设置 IsExtendButtonsInRowHeader=true 使扩展按钮在行前面显示

通过设置 EditDialogDraggable="true" 使编辑弹出框可拖拽

当设置列的 EditTemplate 时,组件自动生成表单维护 UI 时使用此模板作为呈现 UI

Demo

通过设置姓名列的 EditTemplate 自定义编辑时使用下拉框来选择姓名
本例中 Name 列为自定义组件 TableNameDrop,新建时默认为 请选择 ...

通过设置表格的 EditMode 属性,设置组件是弹窗编辑行数据还是行内编辑数据

Demo

EditMode 为枚举类型其值分别为:Popup EditForm InCell 其默认值为 Popup 弹窗编辑行数据

本例中设置数据源 Items 为双向绑定,特别适用与父子表录入,保存时直接使用数据源即可

EditForm 模式示例

InCell 模式示例

未提供数据操作回调方法时组件自动寻找注册的数据服务进行对数据的增删改查

Demo

通过注册数据服务进行增、删、改、查的数据库操作,而无需对以下回调委托进行赋值,优先级别为有回调方法优先调用回调方法,如无则调用注入服务进行数据操作

  • OnAddAsync
  • OnDeleteAsync
  • OnSaveAsync
  • OnQueryAsync
Startup 文件注入数据服务 实现原理与用法介绍
自定义数据服务
开启使用注入数据服务后,可通过设置 DataServices 参数对组件进行单独设置,如未设置内部使用注入服务提供的实例

services.AddTableDemoDataService();

通过设置表格的 DataService 属性,使用独立的数据服务进行对数据的增删改查

Demo

自定义数据服务

开启使用注入数据服务后,可通过设置 DataServices 参数对组件进行单独设置,如未设置内部使用注入服务提供的实例
本例中通过设置 EditDialogShowMaximizeButton 参数,使编辑弹窗中显示 最大化 按钮

services.AddTableDemoDataService();
@page "/tables/edit"

<h3>Table 表格</h3>

<h4>常用于单表维护,通过属性配置实现简单的增、删、改、查、排序、过滤、搜索等常用功能,通过 <code>Template</code> 的高级用法能实现非常复杂的业务需求功能</h4>

<DemoBlock Title="具有单表维护功能的表格" Introduction="设置 <code>ShowSearch</code> 显示查询组件" Name="ShowSearch">
    <p>本例中设置 <code>Count</code> 右侧对齐,<code>Complete</code> 列设置为居中对齐,布尔类型列自动渲染成 <code>Switch</code> 组件</p>
    <Table TItem="Foo" IsAutoCollapsedToolbarButton="false"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true" IsMultipleSelect="true"
           ShowToolbar="true" ShowExtendButtons="true" ShowSkeleton="true" IsExtendButtonsInRowHeader="true"
           OnQueryAsync="@OnQueryAsync" OnAddAsync="@OnAddAsync" OnSaveAsync="@OnSaveAsync" OnDeleteAsync="@OnDeleteAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Education" />
            <TableColumn @bind-Field="@context.Count" Align="Alignment.Right" />
            <TableColumn @bind-Field="@context.Complete" Align="Alignment.Center" />
        </TableColumns>
        <EditTemplate>
            <div class="row g-3 form-inline">
                <div class="col-12 col-sm-6">
                    <BootstrapInput @bind-Value="@context.Name" placeholder="不可为空,50字以内" maxlength="50" />
                </div>
                <div class="col-12 col-sm-6">
                    <BootstrapInput @bind-Value="@context.Address" placeholder="不可为空,50字以内" maxlength="50" />
                </div>
                <div class="col-12 col-sm-6">
                    <DateTimePicker @bind-Value="@context.DateTime" />
                </div>
                <div class="col-12 col-sm-6">
                    <Select @bind-Value="@context.Education" />
                </div>
                <div class="col-12 col-sm-6">
                    <BootstrapInputNumber @bind-Value="@context.Count" ShowButton="true" />
                </div>
                <div class="col-12 col-sm-6">
                    <Switch @bind-Value="@context.Complete" ShowInnerText="true" />
                </div>
            </div>
        </EditTemplate>
    </Table>
</DemoBlock>

<DemoBlock Title="自动生成单表维护功能的表格" Introduction="当设置了 <code>OnAddAsync</code> 或者 <code>OnSaveAsync</code> 回调委托方法时,如果未设置 <code>EditTemplate</code> 编辑模板时,组件会尝试自动生成表单维护 UI" Name="OnAddAsync">
    <p id="anchor2">通过设置 <code>TItem</code> 泛型约束的类实例 <code>Foo</code> 属性的 <code>[Required]</code> 等验证标签即可实现客户端验证</p>
    <p>数据绑定类型为可为空类型时自动允许为空,如日期绑定列为 <code>DateTime?</code> 类型</p>
    <p>数据绑定类型为数值类型时如,如数量绑定列为 <code>int</code> 类型,自动进行数值验证</p>
    <p>表格呈现的有些数据列是计算得到的结果,此种类型的列是无法参与编辑的,通过设置 <code>Editable=false</code> 自动生成编辑 UI 时就不会生成此列编辑组件,如本示例中 <code>Count</code> 列在编辑弹窗中是不出现的</p>
    <p>通过设置 <code>Readonly=true</code> 自动生成编辑 UI 会将此字段进行只读处理,新建时请对 <code>Model</code> 进行默认值赋值</p>
    <p>通过设置 <code>IsExtendButtonsInRowHeader=true</code> 使扩展按钮在行前面显示</p>
    <p>通过设置 <code>EditDialogDraggable="true"</code> 使编辑弹出框可拖拽</p>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true" IsMultipleSelect="true" EditDialogIsDraggable="true"
           ShowToolbar="true" ShowExtendButtons="true" ShowSkeleton="true" IsExtendButtonsInRowHeader="true"
           OnQueryAsync="@OnQueryAsync"
           OnAddAsync="@OnAddAsync" OnSaveAsync="@OnSaveAsync" OnDeleteAsync="@OnDeleteAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" />
            <TableColumn @bind-Field="@context.Address" Readonly="true" />
            <TableColumn @bind-Field="@context.Education" />
            <TableColumn @bind-Field="@context.Count" Editable="false" />
            <TableColumn @bind-Field="@context.Complete" />
        </TableColumns>
    </Table>
</DemoBlock>

<DemoBlock Title="自定义列编辑模板" Introduction="当设置列的 <code>EditTemplate</code> 时,组件自动生成表单维护 UI 时使用此模板作为呈现 UI" Name="EditTemplate">
    <p>
        <div>通过设置姓名列的 <code>EditTemplate</code> 自定义编辑时使用下拉框来选择姓名</div>
        <div>本例中 <code>Name</code> 列为自定义组件 <code>TableNameDrop</code>,新建时默认为 <code>请选择 ...</code></div>
    </p>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true" IsMultipleSelect="true" IsExtendButtonsInRowHeader="true"
           ShowToolbar="true" ShowExtendButtons="true" ShowSkeleton="true"
           OnQueryAsync="@OnQueryAsync"
           OnAddAsync="@OnAddAsync" OnSaveAsync="@OnSaveAsync" OnDeleteAsync="@OnDeleteAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name">
                <EditTemplate Context="value">
                    <div class="col-12 col-sm-6">
                        <TablesNameDrop Model="value" />
                    </div>
                </EditTemplate>
            </TableColumn>
            <TableColumn @bind-Field="@context.Address" Rows="3" />
            <TableColumn @bind-Field="@context.Count" />
            <TableColumn @bind-Field="@context.Complete" />
        </TableColumns>
    </Table>
</DemoBlock>


<DemoBlock Title="设置编辑模式" Introduction="通过设置表格的 <code>EditMode</code> 属性,设置组件是弹窗编辑行数据还是行内编辑数据" Name="EditMode">
    <p id="anchor4"><code>EditMode</code> 为枚举类型其值分别为:<code>Popup</code> <code>EditForm</code> <code>InCell</code> 其默认值为 <code>Popup</code> 弹窗编辑行数据</p>
    <p>本例中设置数据源 <code>Items</code> 为双向绑定,特别适用与父子表录入,保存时直接使用数据源即可</p>
    <p><code>EditForm</code> 模式示例</p>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true" IsMultipleSelect="true"
           ShowToolbar="true" ShowExtendButtons="true" ShowSkeleton="true"
           AddModalTitle="增加测试数据窗口" EditModalTitle="编辑测试数据窗口"
           OnQueryAsync="@OnQueryAsync" EditMode="EditMode.EditForm"
           OnAddAsync="@OnAddAsync" OnSaveAsync="@OnSaveAsync" OnDeleteAsync="@OnDeleteAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Education" />
            <TableColumn @bind-Field="@context.Count" />
            <TableColumn @bind-Field="@context.Complete" />
        </TableColumns>
    </Table>

    <p id="anchor5" class="mt-3"><code>InCell</code> 模式示例</p>
    <RadioList @bind-Value="InsertMode" class="mb-3" />
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true" IsMultipleSelect="true"
           ShowToolbar="true" ShowExtendButtons="true" ShowSkeleton="true"
           AddModalTitle="增加测试数据窗口" EditModalTitle="编辑测试数据窗口"
           EditMode="EditMode.InCell" @bind-Items="@BindItems" InsertRowMode="InsertMode">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" />
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Education" />
            <TableColumn @bind-Field="@context.Count" />
            <TableColumn @bind-Field="@context.Complete" />
        </TableColumns>
    </Table>
</DemoBlock>

<DemoBlock Title="使用注入数据服务" Introduction="未提供数据操作回调方法时组件自动寻找注册的数据服务进行对数据的增删改查" Name="InjectDataService">
    <p id="anchor6">
        通过注册数据服务进行增、删、改、查的数据库操作,而无需对以下回调委托进行赋值,优先级别为有回调方法优先调用回调方法,如无则调用注入服务进行数据操作
        <ul class="ul-demo mb-3">
            <li><code>OnAddAsync</code></li>
            <li><code>OnDeleteAsync</code></li>
            <li><code>OnSaveAsync</code></li>
            <li><code>OnQueryAsync</code></li>
        </ul>
        <div class="mb-3">Startup 文件注入数据服务 <a href="@DataServiceUrl" target="_blank">实现原理与用法介绍</a></div>
        <b>自定义数据服务</b>
        <div class="mt-1">开启使用注入数据服务后,可通过设置 <code>DataServices</code> 参数对组件进行单独设置,如未设置内部使用注入服务提供的实例</div>
    </p>
    <Pre class="no-highlight mt-3">services.AddTableDemoDataService();</Pre>
    <Table TItem="Foo"
           IsPagination="true" PageItemsSource="@PageItemsSource"
           IsStriped="true" IsBordered="true" IsMultipleSelect="true" AutoGenerateColumns="true"
           ShowToolbar="true" ShowExtendButtons="true" ShowSkeleton="true">
        <TableColumns>
            <TableColumn @bind-Field="@context.Hobby" Items="@Hobbys" />
        </TableColumns>
    </Table>
</DemoBlock>

<DemoBlock Title="使用自定义数据服务" Introduction="通过设置表格的 <code>DataService</code> 属性,使用独立的数据服务进行对数据的增删改查" Name="DataService">
    <p id="anchor7">
        <b>自定义数据服务</b>
        <div class="mt-1">开启使用注入数据服务后,可通过设置 <code>DataServices</code> 参数对组件进行单独设置,如未设置内部使用注入服务提供的实例</div>
        <div class="mt-1">本例中通过设置 <code>EditDialogShowMaximizeButton</code> 参数,使编辑弹窗中显示 <b>最大化</b> 按钮</div>
    </p>
    <Pre class="no-highlight mt-3">services.AddTableDemoDataService();</Pre>
    <Table TItem="Foo" EditDialogShowMaximizeButton="true"
           IsPagination="true" PageItemsSource="@PageItemsSource" DataService="@CustomerDataService"
           IsStriped="true" IsBordered="true" IsMultipleSelect="true" AutoGenerateColumns="true"
           ShowToolbar="true" ShowExtendButtons="true" ShowSkeleton="true">
        <TableColumns>
            <TableColumn @bind-Field="@context.Hobby" Items="@Hobbys" />
        </TableColumns>
    </Table>
</DemoBlock>
// 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.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;

namespace BootstrapBlazor.Shared.Samples.Table;

/// <summary>
/// 表单编辑功能示例
/// </summary>
public partial class TablesEdit
{
    [Inject]
    [NotNull]
    private IStringLocalizer<Foo>? Localizer { get; set; }

    [Inject]
    [NotNull]
    private IOptionsMonitor<WebsiteOptions>? WebsiteOption { get; set; }

    private static IEnumerable<int> PageItemsSource => new int[] { 4, 10, 20 };

    [NotNull]
    private IEnumerable<SelectedItem>? Hobbys { get; set; }

    [NotNull]
    private List<Foo>? Items { get; set; }

    [NotNull]
    private IEnumerable<Foo>? BindItems { get; set; }

    private InsertRowMode InsertMode { get; set; } = InsertRowMode.Last;

    private string DataServiceUrl => $"{WebsiteOption.CurrentValue.BootstrapBlazorLink}/wikis/Table%20%E7%BB%84%E4%BB%B6%E6%95%B0%E6%8D%AE%E6%9C%8D%E5%8A%A1%E4%BB%8B%E7%BB%8D?sort_id=3207977";

    /// <summary>
    /// OnInitialized 方法
    /// </summary>
    protected override void OnInitialized()
    {
        base.OnInitialized();

        Hobbys = Foo.GenerateHobbys(Localizer);
        Items = Foo.GenerateFoo(Localizer);

        BindItems = Foo.GenerateFoo(Localizer).Take(5).ToList();

        CustomerDataService = new FooDataService<Foo>(Localizer);
    }

    private static Task<Foo> OnAddAsync() => Task.FromResult(new Foo() { DateTime = DateTime.Now, Address = $"自定义地址  {DateTime.Now.Second}" });

    private Task<bool> OnSaveAsync(Foo item, ItemChangedType changedType)
    {
        // 增加数据演示代码
        if (changedType == ItemChangedType.Add)
        {
            item.Id = Items.Max(i => i.Id) + 1;
            Items.Add(item);
        }
        else
        {
            var oldItem = Items.FirstOrDefault(i => i.Id == item.Id);
            if (oldItem != null)
            {
                oldItem.Name = item.Name;
                oldItem.Address = item.Address;
                oldItem.DateTime = item.DateTime;
                oldItem.Count = item.Count;
                oldItem.Complete = item.Complete;
                oldItem.Education = item.Education;
            }
        }
        return Task.FromResult(true);
    }

    private Task<bool> OnDeleteAsync(IEnumerable<Foo> items)
    {
        items.ToList().ForEach(i => Items.Remove(i));
        return Task.FromResult(true);
    }

    private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions options)
    {
        IEnumerable<Foo> items = Items;

        // 过滤
        var isFiltered = false;
        if (options.Filters.Any())
        {
            items = items.Where(options.Filters.GetFilterFunc<Foo>());
            isFiltered = true;
        }

        // 排序
        var isSorted = false;
        if (!string.IsNullOrEmpty(options.SortName))
        {
            var invoker = Foo.GetNameSortFunc();
            items = invoker(items, options.SortName, options.SortOrder);
            isSorted = true;
        }

        // 设置记录总数
        var total = items.Count();

        // 内存分页
        items = items.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList();

        return Task.FromResult(new QueryData<Foo>()
        {
            Items = items,
            TotalCount = total,
            IsSorted = isSorted,
            IsFiltered = isFiltered,
            IsSearch = true
        });
    }

    [NotNull]
    private IDataService<Foo>? CustomerDataService { get; set; }

    private class FooDataService<TModel> : TableDemoDataService<TModel> where TModel : class, new()
    {
        public FooDataService(IStringLocalizer<TModel> localizer) : base(localizer)
        {

        }
    }
}

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
Seems like the connection with the server has been lost. It can be due to poor or broken network. Please hang on while we're trying to reconnect...
Oh snap! Failed to reconnect with the server. This is typically caused by a longer network outage, or if the server has been taken down. You can try to reconnect, but if that does not work, you need to reload the page.
Oh man! The server rejected the attempt to reconnect. The only option now is to reload the page, but be prepared that it won't work, since this is typically caused by a failure on the server.
Bootstrap Blazor 组件库 更新到 6.6.0

首先感谢您对本套组件的关注,本目前本套组件已经拥有超过 120 个组件,本组件是基于 Bootstrap 风格的 Blazor 企业级组件库,提供如布局、导航、表单、数据、通知、图标、语音等几大类通用组件,每一个组件都经过静心设计,具有模块化、响应式和优秀的性能。从更多实际场景出发,满足多种场景的需求,极大的减少开发者时间成本,大大缩短开发周期,大幅提高开发效率,并提供了一套 通用权限管理系统 示例工程。Bootstrap Blazor 产品是由一支专业的全职技术团队进行维护,高效的响应速度,多元化的解决方案,长期提供支持,并提供企业级支持。目前已在多家知名国企内部使用,项目最高在线 1200 人稳定运行。右侧为国内人数最多的中文 Blazor QQ 社区二维码,欢迎扫描加群。

组件更新到 6.6.0 更新日志 [传送门] 如果组件给您带来了方便,请您帮忙给项目点亮 Star github gitee

QQGroup
QQ 795206915