Skip to content

Commit 583c3fc

Browse files
committed
!3763 feat(#I6AKUV): add Collapsable/IsAccordion parameter on ListView
* chore: bump verson 7.2.3 * doc: 更新资源文件 * doc: 增加文档 * doc: 增加分组折叠效果示例 * feat: 增加默认分组样式 * feat: 增加可收缩与手风琴效果 * refactor: 更新分组手风琴效果样式 * refactor: 样式参数化 * doc: 更新注释文档 * refactor: 重构内部逻辑提高显示速度
1 parent b645333 commit 583c3fc

9 files changed

Lines changed: 189 additions & 47 deletions

File tree

src/BootstrapBlazor.Shared/Locales/en.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4240,11 +4240,17 @@
42404240
"PaginationIntro": "Set the <code>Pageable</code> display paginated components",
42414241
"GroupTitle": "Group display",
42424242
"GroupIntro": "Set up grouping <code>GroupName</code> data",
4243+
"CollapsableTitle": "Collapsable",
4244+
"CollapsableIntro": "Set up grouping can collapable via <code>Collapsable=\"true\"</code>",
4245+
"IsAccordionTitle": "Group accordion",
4246+
"IsAccordionIntro": "Set up grouping can accordion via <code>IsAccordion=\"true\"</code>",
42434247
"Items": "Component data source",
42444248
"Pageable": "Whether to paginated",
42454249
"HeaderTemplate": "ListView Header template",
42464250
"BodyTemplate": "ListView Body template",
42474251
"FooterTemplate": "ListView Footer template",
4252+
"Collapsable": "Group collapsable",
4253+
"IsAccordion": "Group accordion",
42484254
"OnQueryAsync": "Asynchronous query callback method",
42494255
"OnListViewItemClick": "The ListView element calls back when it clicks on the delegate",
42504256
"QueryAsync": "Manually query data methods"

src/BootstrapBlazor.Shared/Locales/zh.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4247,11 +4247,17 @@
42474247
"PaginationIntro": "设置 <code>Pageable</code> 显示分页组件",
42484248
"GroupTitle": "分组显示",
42494249
"GroupIntro": "设置 <code>GroupName</code> 数据进行分组显示",
4250+
"CollapsableTitle": "分组折叠",
4251+
"CollapsableIntro": "设置 <code>Collapsable=\"true\"</code> 使分组信息可折叠",
4252+
"IsAccordionTitle": "分组手风琴",
4253+
"IsAccordionIntro": "设置 <code>IsAccordion=\"true\"</code> 使分组信息折叠手风琴效果",
42504254
"Items": "组件数据源",
42514255
"Pageable": "是否分页",
42524256
"HeaderTemplate": "ListView Header 模板",
42534257
"BodyTemplate": "ListView Body 模板",
42544258
"FooterTemplate": "ListView Footer 模板",
4259+
"Collapsable": "分组数据折叠",
4260+
"IsAccordion": "分组数据手风琴效果",
42554261
"OnQueryAsync": "异步查询回调方法",
42564262
"OnListViewItemClick": "ListView元素点击时回调委托",
42574263
"QueryAsync": "手工查询数据方法"

src/BootstrapBlazor.Shared/Samples/ListViews.razor

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,42 @@
6767
</div>
6868
</DemoBlock>
6969

70+
<DemoBlock Title="@Localizer["CollapsableTitle"]" Introduction="@Localizer["CollapsableIntro"]" Name="Collapsable">
71+
<div class="listview-demo">
72+
<ListView TItem="Product" GroupName="@(p => p.Category)" OnQueryAsync="@OnQueryAsync" Collapsable="true">
73+
<HeaderTemplate>
74+
<div>@Localizer["ProductListText"]</div>
75+
</HeaderTemplate>
76+
<BodyTemplate>
77+
<Card>
78+
<BodyTemplate>
79+
<img src="@context.ImageUrl" />
80+
<div class="listview-demo-desc">@context.Description</div>
81+
</BodyTemplate>
82+
</Card>
83+
</BodyTemplate>
84+
</ListView>
85+
</div>
86+
</DemoBlock>
87+
88+
<DemoBlock Title="@Localizer["IsAccordionTitle"]" Introduction="@Localizer["IsAccordionIntro"]" Name="IsAccordion">
89+
<div class="listview-demo">
90+
<ListView TItem="Product" GroupName="@(p => p.Category)" OnQueryAsync="@OnQueryAsync" Collapsable="true" IsAccordion="true">
91+
<HeaderTemplate>
92+
<div>@Localizer["ProductListText"]</div>
93+
</HeaderTemplate>
94+
<BodyTemplate>
95+
<Card>
96+
<BodyTemplate>
97+
<img src="@context.ImageUrl" />
98+
<div class="listview-demo-desc">@context.Description</div>
99+
</BodyTemplate>
100+
</Card>
101+
</BodyTemplate>
102+
</ListView>
103+
</div>
104+
</DemoBlock>
105+
70106
<AttributeTable Items="GetAttributes()"></AttributeTable>
71107

72108
<MethodTable Items="GetMethods()"></MethodTable>

src/BootstrapBlazor.Shared/Samples/ListViews.razor.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ private Task OnListViewItemClick(Product item)
8383
ValueList = " — ",
8484
DefaultValue = " — "
8585
},
86+
new AttributeItem(){
87+
Name = nameof(ListView<Foo>.Collapsable),
88+
Description = Localizer["Collapsable"],
89+
Type = "bool",
90+
ValueList = "true|false",
91+
DefaultValue = "false"
92+
},
93+
new AttributeItem(){
94+
Name = nameof(ListView<Foo>.IsAccordion),
95+
Description = Localizer["IsAccordion"],
96+
Type = "bool",
97+
ValueList = "true|false",
98+
DefaultValue = "false"
99+
},
86100
new AttributeItem() {
87101
Name = "OnQueryAsync",
88102
Description = Localizer["OnQueryAsync"],

src/BootstrapBlazor/BootstrapBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>7.2.3-beta03</Version>
4+
<Version>7.2.3</Version>
55
</PropertyGroup>
66

77
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
11
.listview {
2-
border: 1px solid rgba(0,0,0,.125);
3-
border-radius: 0.25rem;
2+
--bb-lv-header-padding: .5rem 1rem;
3+
--bb-lv-header-bg: #dee2e6;
4+
--bb-lv-border-color: var(--bs-border-color);
5+
--bb-lv-item-trans: border .3s linear;
6+
--bb-lv-item-border-hover-color: #409eff;
7+
--bb-lv-item-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
8+
--bb-lv-body-padding: 1rem 0 0 1rem;
9+
--bb-lv-body-item-margin: 0 1rem 1rem 0;
10+
--bb-lv-footer-padding: 1rem;
11+
border: 1px solid var(--bb-lv-border-color);
12+
border-radius: var(--bs-border-radius);
413
width: 100%;
514
height: 100%;
615
display: flex;
716
flex-flow: column nowrap;
817
}
918

1019
.listview .listview-header {
11-
padding: 1rem;
12-
border-bottom-color: inherit;
13-
border-bottom-width: 1px;
14-
border-bottom-style: solid;
20+
padding: var(--bb-lv-header-padding);
21+
border-bottom: 1px solid var(--bb-lv-border-color);
1522
}
1623

1724
.listview.is-vertical .listview-body {
1825
display: block;
1926
}
2027

2128
.listview .listview-body {
22-
padding: 1rem 0 0 1rem;
29+
padding: var(--bb-lv-body-padding);
2330
position: relative;
2431
overflow: auto;
2532
display: flex;
@@ -28,17 +35,25 @@
2835
align-content: flex-start;
2936
}
3037

38+
.listview .listview-body.is-group {
39+
padding: 0;
40+
}
41+
3142
.listview .listview-body .listview-item {
32-
margin: 0 1rem 1rem 0;
43+
margin: var(--bb-lv-body-item-margin);
3344
}
3445

46+
.listview .listview-body .listview-item .card {
47+
transition: var(--bb-lv-item-trans);
48+
}
49+
3550
.listview .listview-body .listview-item:hover .card {
3651
cursor: pointer;
37-
border: 1px solid #409eff;
52+
border: 1px solid var(--bb-lv-item-border-hover-color);
3853
}
3954

4055
.listview .listview-body .listview-item .card {
41-
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
56+
box-shadow: var(--bb-lv-item-shadow);
4257
}
4358

4459
.listview .listview-body .listview-item-group {
@@ -48,19 +63,37 @@
4863
position: relative;
4964
}
5065

51-
.listview .listview-body .listview-item-group:after {
52-
content: "";
53-
position: absolute;
54-
top: calc(-50%);
55-
left: -1rem;
56-
right: 0;
57-
background-color: rgba(0,0,0,.1);
58-
height: calc(200%);
66+
.listview .listview-body .accordion {
67+
--bs-accordion-inner-border-radius: 0;
68+
--bs-accordion-border-width: 0;
69+
flex: 1;
70+
margin: 0;
71+
}
72+
73+
.listview .listview-body .accordion-header {
74+
border-top: 1px solid var(--bb-lv-border-color);
75+
}
76+
77+
.listview .listview-body .accordion-header .accordion-button {
78+
padding: var(--bb-lv-header-padding);
5979
}
6080

81+
.listview .listview-body .accordion-body {
82+
display: flex;
83+
flex-wrap: wrap;
84+
padding: var(--bb-lv-body-padding);
85+
}
86+
87+
.listview .listview-body .accordion-item:last-child .accordion-header {
88+
border-bottom: 1px solid var(--bb-lv-border-color);
89+
}
90+
91+
.listview .listview-body > .accordion-item .accordion-header {
92+
padding: var(--bb-lv-header-padding);
93+
background-color: var(--bb-lv-header-bg);
94+
}
95+
6196
.listview .listview-footer {
62-
padding: 1rem;
63-
border-top-color: inherit;
64-
border-top-width: 1px;
65-
border-top-style: solid;
97+
padding: var(--bb-lv-footer-padding);
98+
border-top: 1px solid var(--bb-lv-border-color);
6699
}

src/BootstrapBlazor/Components/ListView/ListView.razor

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,51 @@
99
@HeaderTemplate
1010
</div>
1111
}
12-
<div class="listview-body">
13-
@if (Items != null && BodyTemplate != null)
12+
<div class="@BodyClassString">
13+
@if (BodyTemplate != null)
1414
{
1515
if (GroupName == null)
1616
{
17-
foreach (var item in Items)
17+
foreach (var item in Rows)
1818
{
1919
<div class="listview-item" @onclick="@(e => OnClick(item))">
2020
@BodyTemplate.Invoke(item)
2121
</div>
2222
}
2323
}
24+
else if(Collapsable)
25+
{
26+
<Collapse IsAccordion="IsAccordion" OnCollapseChanged="OnCollapseChanged!">
27+
<CollapseItems>
28+
@foreach (var key in Rows.GroupBy(GroupName).OrderBy(k => k.Key))
29+
{
30+
<CollapseItem @key="@key.Key" Text="@key.Key?.ToString()">
31+
@foreach (var item in key)
32+
{
33+
<div class="listview-item" @onclick="@(e => OnClick(item))">
34+
@BodyTemplate.Invoke(item)
35+
</div>
36+
}
37+
</CollapseItem>
38+
}
39+
</CollapseItems>
40+
</Collapse>
41+
}
2442
else
2543
{
26-
foreach (var key in Items.GroupBy(GroupName).OrderBy(k => k.Key))
44+
foreach (var key in Rows.GroupBy(GroupName).OrderBy(k => k.Key))
2745
{
28-
<div class="listview-item-group">@key.Key</div>
29-
@foreach (var item in key)
30-
{
31-
<div class="listview-item" @onclick="@(e => OnClick(item))">
32-
@BodyTemplate.Invoke(item)
46+
<div class="accordion-item">
47+
<div class="accordion-header">@key.Key</div>
48+
<div class="accordion-body">
49+
@foreach (var item in key)
50+
{
51+
<div class="listview-item" @onclick="@(e => OnClick(item))">
52+
@BodyTemplate.Invoke(item)
53+
</div>
54+
}
3355
</div>
34-
}
56+
</div>
3557
}
3658
}
3759
}

src/BootstrapBlazor/Components/ListView/ListView.razor.cs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ namespace BootstrapBlazor.Components;
77
/// <summary>
88
/// ListView 组件基类
99
/// </summary>
10-
public partial class ListView<TItem> : BootstrapComponentBase where TItem : class, new()
10+
public partial class ListView<TItem> : BootstrapComponentBase
1111
{
12-
/// <summary>
13-
/// Card组件样式
14-
/// </summary>
15-
protected virtual string? ClassString => CssBuilder.Default("listview")
12+
private string? ClassString => CssBuilder.Default("listview")
1613
.AddClass("is-vertical", IsVertical)
1714
.AddClassFromAttributes(AdditionalAttributes)
1815
.Build();
1916

17+
private string? BodyClassString => CssBuilder.Default("listview-body")
18+
.AddClass("is-group", GroupName != null)
19+
.Build();
20+
2021
/// <summary>
2122
/// 获得/设置 CardHeard
2223
/// </summary>
@@ -27,10 +28,13 @@ namespace BootstrapBlazor.Components;
2728
/// 获得/设置 BodyTemplate
2829
/// </summary>
2930
[Parameter]
31+
#if NET6_0_OR_GREATER
32+
[EditorRequired]
33+
#endif
3034
public RenderFragment<TItem>? BodyTemplate { get; set; }
3135

3236
/// <summary>
33-
/// 获得/设置 FooterTemplate
37+
/// 获得/设置 FooterTemplate 默认 null 未设置 设置值后 <see cref="Pageable"/> 参数不起作用,请自行实现分页功能
3438
/// </summary>
3539
[Parameter]
3640
public RenderFragment? FooterTemplate { get; set; }
@@ -42,17 +46,35 @@ namespace BootstrapBlazor.Components;
4246
public IEnumerable<TItem>? Items { get; set; }
4347

4448
/// <summary>
45-
/// 获得/设置 是否分页 默认为 false 不分页
49+
/// 获得/设置 是否分页 默认为 false 不分页 设置 <see cref="FooterTemplate"/> 时分页功能自动被禁用
4650
/// </summary>
4751
[Parameter]
4852
public bool Pageable { get; set; }
4953

5054
/// <summary>
51-
/// 获得/设置 分组名称
55+
/// 获得/设置 分组 Lambda 表达式 默认 null
5256
/// </summary>
5357
[Parameter]
5458
public Func<TItem, object?>? GroupName { get; set; }
5559

60+
/// <summary>
61+
/// 获得/设置 是否可折叠 默认 false 需要开启分组设置 <see cref="GroupName"/>
62+
/// </summary>
63+
[Parameter]
64+
public bool Collapsable { get; set; }
65+
66+
/// <summary>
67+
/// 获得/设置 是否手风琴效果 默认 false 需要开启可收缩设置 <see cref="Collapsable"/>
68+
/// </summary>
69+
[Parameter]
70+
public bool IsAccordion { get; set; }
71+
72+
/// <summary>
73+
/// 获得/设置 CollapseItem 展开收缩时回调方法 默认 false 需要开启可收缩设置 <see cref="Collapsable"/>
74+
/// </summary>
75+
[Parameter]
76+
public Func<CollapseItem, Task>? OnCollapseChanged { get; set; }
77+
5678
/// <summary>
5779
/// 异步查询回调方法
5880
/// </summary>
@@ -87,16 +109,19 @@ namespace BootstrapBlazor.Components;
87109
/// </summary>
88110
protected int TotalCount { get; set; }
89111

112+
/// <summary>
113+
/// 数据集合内部使用
114+
/// </summary>
115+
protected IEnumerable<TItem> Rows => Items ?? Enumerable.Empty<TItem>();
116+
90117
/// <summary>
91118
/// <inheritdoc/>
92119
/// </summary>
93-
/// <param name="firstRender"></param>
94-
/// <returns></returns>
95-
protected override async Task OnAfterRenderAsync(bool firstRender)
120+
protected override async Task OnParametersSetAsync()
96121
{
97-
if (firstRender && Items == null)
122+
if (Items == null)
98123
{
99-
await QueryAsync();
124+
await QueryData();
100125
}
101126
}
102127

src/BootstrapBlazor/wwwroot/css/bootstrap.blazor.bundle.min.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)