!62 增加功能:Blazor 模式下支持固定表头设置
Merge pull request !62 from Argo/dev-blazor-table
This commit is contained in:
commit
65fda668bf
|
@ -78,6 +78,12 @@ namespace Bootstrap.Admin.Components
|
|||
[Parameter]
|
||||
public RenderFragment<TItem>? EditTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否固定表头 默认为 false 不固定表头
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool FixedHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 Table 实例
|
||||
/// </summary>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using Bootstrap.Admin.Shared;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -60,6 +61,30 @@ namespace Bootstrap.Admin.Components
|
|||
[Parameter]
|
||||
public RenderFragment? TableFooter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否固定表头 默认为 false 不固定表头
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool FixedHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得 IJSRuntime 实例
|
||||
/// </summary>
|
||||
[Inject]
|
||||
protected IJSRuntime? JSRuntime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否自适应高度 默认为 false 不自适应高度
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool AutoHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否显示搜索框 默认为 false 不显示搜索框
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowSearch { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 数据集合
|
||||
/// </summary>
|
||||
|
@ -185,6 +210,18 @@ namespace Bootstrap.Admin.Components
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
protected override async System.Threading.Tasks.Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (FixedHeader)
|
||||
{
|
||||
// 调用客户端脚本 resetWith
|
||||
await JSRuntime.InitTableAsync(RetrieveId(), firstRender);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击页码调用此方法
|
||||
/// </summary>
|
||||
|
@ -347,5 +384,10 @@ namespace Bootstrap.Admin.Components
|
|||
}
|
||||
ShowMessage("删除数据", "删除数据" + (result ? "成功" : "失败"), result ? ToastCategory.Success : ToastCategory.Error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 Id 字符串
|
||||
/// </summary>
|
||||
public string RetrieveId() => $"{Id}_table";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,5 +97,13 @@ namespace Bootstrap.Admin.Extensions
|
|||
/// <param name="showCardTitle"></param>
|
||||
/// <param name="fixedTableHeader"></param>
|
||||
public static void SetWebSettings(this IJSRuntime? jSRuntime, bool showSidebar, bool showCardTitle, bool fixedTableHeader) => jSRuntime.InvokeVoidAsync("$.setWebSettings", showSidebar, showCardTitle, fixedTableHeader);
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 Table 组件
|
||||
/// </summary>
|
||||
/// <param name="jSRuntime"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="firstRender"></param>
|
||||
public static ValueTask InitTableAsync(this IJSRuntime? jSRuntime, string id, bool firstRender) => jSRuntime.InvokeVoidAsync("$.initTable", id, firstRender);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@inherits DictsBase
|
||||
|
||||
<EditPage Id="dict" TItem="Bootstrap.Security.BootstrapDict" SubmitModalTitle="字典编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<EditPage Id="dict" FixedHeader="@FixedHeader" TItem="Bootstrap.Security.BootstrapDict" SubmitModalTitle="字典编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<QueryBody>
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.Category" maxlength="50" />
|
||||
<Select ColumnClass="col-sm-auto" Items="QueryDefine" TItem="int" @bind-Value="@context.Define" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@inherits GroupsBase
|
||||
|
||||
<EditPage Id="group" TItem="Bootstrap.DataAccess.Group" SubmitModalTitle="部门编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<EditPage Id="group" FixedHeader="@FixedHeader" TItem="Bootstrap.DataAccess.Group" SubmitModalTitle="部门编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<QueryBody>
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.GroupName" maxlength="50" />
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.Description" maxlength="50" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@inherits MenusBase
|
||||
|
||||
<EditPage Id="role" TItem="Bootstrap.Security.BootstrapMenu" SubmitModalTitle="菜单编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<EditPage Id="role" FixedHeader="@FixedHeader" TItem="Bootstrap.Security.BootstrapMenu" SubmitModalTitle="菜单编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<QueryBody>
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.Name" maxlength="50" />
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.ParentName" maxlength="50" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@inherits RolesBase
|
||||
|
||||
<EditPage Id="role" TItem="Bootstrap.DataAccess.Role" SubmitModalTitle="角色编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<EditPage Id="role" FixedHeader="@FixedHeader" TItem="Bootstrap.DataAccess.Role" SubmitModalTitle="角色编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<QueryBody>
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.RoleName" maxlength="50" />
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.Description" maxlength="50" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@inherits UsersBase
|
||||
|
||||
<EditPage Id="user" TItem="Bootstrap.DataAccess.User" SubmitModalTitle="用户编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<EditPage Id="user" FixedHeader="@FixedHeader" TItem="Bootstrap.DataAccess.User" SubmitModalTitle="用户编辑窗口" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<QueryBody>
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.UserName" maxlength="50" />
|
||||
<LgbInputText ColumnClass="col-sm-auto" @bind-Value="@context.DisplayName" maxlength="50" />
|
||||
|
|
|
@ -103,6 +103,7 @@ namespace Bootstrap.Pages.Admin.Components
|
|||
/// <returns></returns>
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
QueryModel.Category = "";
|
||||
QueryModel.IsResource = -1;
|
||||
QueryApp.AddRange(DictHelper.RetrieveApps().Select(app => new SelectedItem() { Text = app.Value, Value = app.Key }));
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using Bootstrap.Admin.Components;
|
||||
using Bootstrap.DataAccess;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bootstrap.Pages.Admin.Components
|
||||
{
|
||||
|
@ -8,6 +10,12 @@ namespace Bootstrap.Pages.Admin.Components
|
|||
/// </summary>
|
||||
public abstract class QueryPageBase<TItem> : PageBase where TItem : class, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 是否固定表头 默认为 false 不固定表头
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool FixedHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 TItem 实例
|
||||
/// </summary>
|
||||
|
@ -20,6 +28,14 @@ namespace Bootstrap.Pages.Admin.Components
|
|||
/// <param name="pageItems">每页显示数据条目数量</param>
|
||||
protected abstract QueryData<TItem> Query(int pageIndex, int pageItems);
|
||||
|
||||
/// <summary>
|
||||
/// OnParametersSet 方法
|
||||
/// </summary>
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
FixedHeader = DictHelper.RetrieveFixedTableHeader();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新建方法
|
||||
/// </summary>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
查询结果
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<Table @ref="Table" Id="@Id" TItem="TItem" SubmitModalTitle="@SubmitModalTitle" OnQuery="QueryData" OnAdd="OnAdd" OnDelete="OnDelete" OnSave="OnSave">
|
||||
<Table @ref="Table" Id="@Id" FixedHeader="@FixedHeader" TItem="TItem" SubmitModalTitle="@SubmitModalTitle" OnQuery="QueryData" OnAdd="OnAdd" OnDelete="OnDelete" OnSave="OnSave">
|
||||
<TableToolbarTemplate>
|
||||
@TableToolbarTemplate
|
||||
</TableToolbarTemplate>
|
||||
|
|
|
@ -12,49 +12,120 @@
|
|||
</TableToolbar>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table class="table table-striped table-bordered table-hover table-selected" id="@($"{Id}_table")">
|
||||
<thead>
|
||||
<tr>
|
||||
@if (ShowCheckbox)
|
||||
{
|
||||
<th class="table-col-checkbox"><Checkbox TItem="TItem" SetCheckCallback="CheckState" ToggleCallback="ToggleCheck"></Checkbox></th>
|
||||
}
|
||||
@if (ShowLineNo)
|
||||
{
|
||||
<th class="table-col-lineno">行号</th>
|
||||
}
|
||||
@TableHeader?.Invoke(EditModel)
|
||||
@if (ShowButtons)
|
||||
{
|
||||
<th>@ButtonTemplateHeaderText</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (int index = 0; index < Items.Count(); index++)
|
||||
{
|
||||
<div class="@(FixedHeader ? "table-wrapper table-fixed-header" : "table-wrapper")">
|
||||
@if(FixedHeader)
|
||||
{
|
||||
<div class="fixed-table-header">
|
||||
<table class="table table-bordered table-hover table-selected">
|
||||
<thead>
|
||||
<tr>
|
||||
@if (ShowCheckbox)
|
||||
{
|
||||
<th class="table-col-checkbox"><Checkbox TItem="TItem" SetCheckCallback="CheckState" ToggleCallback="ToggleCheck"></Checkbox></th>
|
||||
}
|
||||
@if (ShowLineNo)
|
||||
{
|
||||
<th class="table-col-lineno">行号</th>
|
||||
}
|
||||
@TableHeader?.Invoke(EditModel)
|
||||
@if (ShowButtons)
|
||||
{
|
||||
<th>@ButtonTemplateHeaderText</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="fixed-table-body invisible">
|
||||
<table class="table table-bordered table-hover table-selected" id="@RetrieveId()">
|
||||
<thead>
|
||||
<tr>
|
||||
@if (ShowCheckbox)
|
||||
{
|
||||
<th class="table-col-checkbox"><Checkbox TItem="TItem" SetCheckCallback="CheckState" ToggleCallback="ToggleCheck"></Checkbox></th>
|
||||
}
|
||||
@if (ShowLineNo)
|
||||
{
|
||||
<th class="table-col-lineno">行号</th>
|
||||
}
|
||||
@TableHeader?.Invoke(EditModel)
|
||||
@if (ShowButtons)
|
||||
{
|
||||
<th>@ButtonTemplateHeaderText</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (int index = 0; index < Items.Count(); index++)
|
||||
{
|
||||
<tr>
|
||||
@if (ShowCheckbox)
|
||||
{
|
||||
<td class="table-col-checkbox"><Checkbox TItem="TItem" Item="Items.ElementAt(index)" SetCheckCallback="item => SelectedItems.Contains(item) ? CheckBoxState.Checked : CheckBoxState.UnChecked" ToggleCallback="ToggleCheck"></Checkbox></td>
|
||||
}
|
||||
@if (ShowLineNo)
|
||||
{
|
||||
<td class="table-col-lineno">@(index + 1 + (PageIndex - 1) * PageItems)</td>
|
||||
}
|
||||
@RowTemplate?.Invoke(Items.ElementAt(index))
|
||||
@if (ShowButtons)
|
||||
{
|
||||
<td>@ButtonTemplate?.Invoke(Items.ElementAt(index))</td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>@TableFooter</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table table-striped table-bordered table-hover table-selected" id="@($"{Id}_table")">
|
||||
<thead>
|
||||
<tr>
|
||||
@if (ShowCheckbox)
|
||||
{
|
||||
<td class="table-col-checkbox"><Checkbox TItem="TItem" Item="Items.ElementAt(index)" SetCheckCallback="item => SelectedItems.Contains(item) ? CheckBoxState.Checked : CheckBoxState.UnChecked" ToggleCallback="ToggleCheck"></Checkbox></td>
|
||||
<th class="table-col-checkbox"><Checkbox TItem="TItem" SetCheckCallback="CheckState" ToggleCallback="ToggleCheck"></Checkbox></th>
|
||||
}
|
||||
@if (ShowLineNo)
|
||||
{
|
||||
<td class="table-col-lineno">@(index + 1 + (PageIndex - 1) * PageItems)</td>
|
||||
<th class="table-col-lineno">行号</th>
|
||||
}
|
||||
@RowTemplate?.Invoke(Items.ElementAt(index))
|
||||
@TableHeader?.Invoke(EditModel)
|
||||
@if (ShowButtons)
|
||||
{
|
||||
<td>@ButtonTemplate?.Invoke(Items.ElementAt(index))</td>
|
||||
<th>@ButtonTemplateHeaderText</th>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>@TableFooter</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (int index = 0; index < Items.Count(); index++)
|
||||
{
|
||||
<tr>
|
||||
@if (ShowCheckbox)
|
||||
{
|
||||
<td class="table-col-checkbox"><Checkbox TItem="TItem" Item="Items.ElementAt(index)" SetCheckCallback="item => SelectedItems.Contains(item) ? CheckBoxState.Checked : CheckBoxState.UnChecked" ToggleCallback="ToggleCheck"></Checkbox></td>
|
||||
}
|
||||
@if (ShowLineNo)
|
||||
{
|
||||
<td class="table-col-lineno">@(index + 1 + (PageIndex - 1) * PageItems)</td>
|
||||
}
|
||||
@RowTemplate?.Invoke(Items.ElementAt(index))
|
||||
@if (ShowButtons)
|
||||
{
|
||||
<td>@ButtonTemplate?.Invoke(Items.ElementAt(index))</td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>@TableFooter</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
}
|
||||
</div>
|
||||
<Pagination PageItems="PageItems" TotalCount="TotalCount" PageIndex="PageIndex" OnPageClick="PageClick" OnPageItemsChange="PageItemsChange"></Pagination>
|
||||
</div>
|
||||
|
|
|
@ -130,16 +130,47 @@ nav .dropdown .nav-link-close.dropdown-toggle:after {
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.bootstrap-table .fixed-table-header {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bootstrap-table .fixed-table-body {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.bootstrap-table .fixed-table-body table {
|
||||
margin-top: -38px;
|
||||
}
|
||||
|
||||
.bootstrap-table .fixed-table-body thead th, .bootstrap-table .fixed-table-header thead th {
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.table-wrapper .table {
|
||||
margin-bottom: 1px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.table-fixed-header {
|
||||
border: solid 1px #dee2e6;
|
||||
}
|
||||
|
||||
.table-fixed-header .table {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.table-fixed-header .table th:last-child {
|
||||
border-right-width: 0;
|
||||
}
|
||||
|
||||
.table-fixed-header .table th:first-child, .table-fixed-header .table td:first-child {
|
||||
border-left-width: 0;
|
||||
}
|
||||
|
||||
.pagination-bar {
|
||||
flex: 1 1 auto;
|
||||
margin-bottom: 1rem;
|
||||
|
|
|
@ -140,10 +140,60 @@
|
|||
var $tabContent = $('section .tab-content');
|
||||
if (showCardTitle) $tabContent.removeClass('no-card-header');
|
||||
else $tabContent.addClass('no-card-header');
|
||||
},
|
||||
resetTableWidth: function (source, target) {
|
||||
// 设置表格宽度
|
||||
target.width(source.width());
|
||||
|
||||
var $table = $(".bootstrap-table");
|
||||
if (fixedTableHeader) $table.attr('data-header', 'fixed');
|
||||
else $table.attr('data-header', 'scroll');
|
||||
// 设置各列宽度
|
||||
var $heads = target.find('th');
|
||||
source.find('th').each(function (index, element) {
|
||||
var header = $heads.get(index);
|
||||
$(header).width($(element).width());
|
||||
});
|
||||
},
|
||||
resetTableHeight(source) {
|
||||
var table = source;
|
||||
var height = 0;
|
||||
do {
|
||||
height += source.position().top;
|
||||
source = source.parent();
|
||||
if (source.hasClass('tab-content')) break;
|
||||
}
|
||||
while (source.length === 1);
|
||||
height = $(window).height() - height - 15;
|
||||
table.height(height);
|
||||
},
|
||||
initTable: function (id, firstRender) {
|
||||
var $table = $('#' + id);
|
||||
var $fixedBody = $table.parents('.fixed-table-body');
|
||||
|
||||
if (firstRender) {
|
||||
// calc height
|
||||
$.resetTableHeight($fixedBody);
|
||||
|
||||
// modify scroll
|
||||
$table.parent().overlayScrollbars({
|
||||
className: 'os-theme-dark',
|
||||
scrollbars: {
|
||||
autoHide: 'leave',
|
||||
autoHideDelay: 100
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var $tableContainer = $table.parents('.table-wrapper');
|
||||
var $tableHeader = $tableContainer.find('.fixed-table-header table');
|
||||
$.resetTableWidth($table, $tableHeader);
|
||||
|
||||
if (firstRender) {
|
||||
$tableContainer.find('.fixed-table-body').removeClass('invisible');
|
||||
|
||||
$(window).on('resize', function () {
|
||||
$.resetTableWidth($table, $tableHeader);
|
||||
$.resetTableHeight($fixedBody);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue