Skip to content

Commit 5e3dab8

Browse files
nhrenArgoZhang
andauthored
feat(LoadMore): add LoadMore component (dotnetcore#6436)
* 增加触底加载LoadMore * refactor: 更新示例文档 * refactor: 更新使用元素视口逻辑 * chore: 撤销更改 * chore: 撤销更改 * chore: 移动组件目录 * doc: 增加多语言支持 * refactor: 调整结构精简样式 * refactor: 增加逻辑检查 * doc: 增加 LoadMore 示例 * refactor: 更改参数名称提高可读性 * doc: 更新示例文档 * feat: 增加阈值参数 * test: 补充 LoadMore 单元测试 * doc: 更新文档 * chore: bump version 9.8.2-beta02 Co-Authored-By: nhren <[email protected]> --------- Co-authored-by: Argo Zhang <[email protected]>
1 parent 4dad565 commit 5e3dab8

File tree

15 files changed

+243
-26
lines changed

15 files changed

+243
-26
lines changed

src/BootstrapBlazor.Server/Components/Samples/IntersectionObservers.razor

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22
@inject IStringLocalizer<IntersectionObservers> Localizer
33
@inject IOptionsMonitor<WebsiteOptions> WebsiteOption
44

5+
<HeadContent>
6+
<style>
7+
.bb-video video {
8+
width: 256px;
9+
}
10+
11+
@@media (min-width: 767.99px) {
12+
.bb-video video {
13+
width: 350px;
14+
}
15+
}
16+
</style>
17+
</HeadContent>
18+
519
<h3>@Localizer["IntersectionObserverTitle"]</h3>
620

721
<h4>@Localizer["IntersectionObserverDescription"]</h4>
@@ -56,23 +70,10 @@
5670
<DemoBlock Title="@Localizer["IntersectionObserverVisibleTitle"]"
5771
Introduction="@Localizer["IntersectionObserverVisibleIntro"]"
5872
Name="Visible">
59-
<HeadContent>
60-
<style>
61-
.bb-video video {
62-
width: 256px;
63-
}
64-
65-
@@media (min-width: 767.99px) {
66-
.bb-video video {
67-
width: 350px;
68-
}
69-
}
70-
</style>
71-
</HeadContent>
7273
<section ignore>
7374
<p>@((MarkupString)Localizer["IntersectionObserverVisibleDesc"].Value)</p>
75+
<div class="text-center @_textColorString">@_videoStateString</div>
7476
</section>
75-
<p class="text-center @_textColorString">@_videoStateString</p>
7677
<IntersectionObserver OnIntersecting="OnVisibleChanged" Threshold="1" AutoUnobserveWhenIntersection="false">
7778
<div class="bb-video-demo scroll">
7879
<div class="bb-video">
@@ -87,8 +88,10 @@
8788
<DemoBlock Title="@Localizer["IntersectionObserverThresholdTitle"]"
8889
Introduction="@Localizer["IntersectionObserverThresholdIntro"]"
8990
Name="Threshold">
90-
<section ignore><p>@((MarkupString)Localizer["IntersectionObserverThresholdDesc"].Value)</p></section>
91-
<p class="text-center">@_thresholdValueString</p>
91+
<section ignore>
92+
<p>@((MarkupString)Localizer["IntersectionObserverThresholdDesc"].Value)</p>
93+
<div class="text-center">@_thresholdValueString</div>
94+
</section>
9295
<IntersectionObserver OnIntersecting="OnThresholdChanged" Threshold="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1" AutoUnobserveWhenIntersection="false">
9396
<div class="bb-list-load scroll" style="height: 200px;">
9497
<div class="d-flex" style="height: 600px; justify-content: center; align-items: center;">
@@ -100,4 +103,24 @@
100103
</IntersectionObserver>
101104
</DemoBlock>
102105

106+
<DemoBlock Title="@Localizer["LoadMoreTitle"]"
107+
Introduction="@Localizer["LoadMoreIntro"]"
108+
Name="LoadMoreComponent">
109+
<section ignore>
110+
<div>@((MarkupString)Localizer["LoadMoreDesc"].Value)</div>
111+
</section>
112+
<div style="height: 400px; overflow: auto;">
113+
<div class="bb-list-demo">
114+
@foreach (var image in _items)
115+
{
116+
<div class="bb-list-item">
117+
<img src="@image" />
118+
</div>
119+
}
120+
</div>
121+
<LoadMore OnLoadMoreAsync="OnLoadMoreItemAsync" CanLoading="_canLoading">
122+
</LoadMore>
123+
</div>
124+
</DemoBlock>
125+
103126
<AttributeTable Items="@GetAttributes()" />

src/BootstrapBlazor.Server/Components/Samples/IntersectionObservers.razor.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ protected override void OnInitialized()
2323
{
2424
base.OnInitialized();
2525

26-
_images = Enumerable.Range(1, 100).Select(i => $"{WebsiteOption.CurrentValue.AssetRootPath}images/default.jpeg").ToList();
27-
_items = Enumerable.Range(1, 20).Select(i => $"https://picsum.photos/160/160?random={i}").ToList();
26+
_images = [.. Enumerable.Range(1, 100).Select(i => $"{WebsiteOption.CurrentValue.AssetRootPath}images/default.jpeg")];
27+
_items = [.. Enumerable.Range(1, 20).Select(i => $"https://picsum.photos/160/160?random={i}")];
2828
}
2929

3030
private Task OnIntersectingAsync(IntersectionObserverEntry entry)
@@ -43,12 +43,21 @@ private async Task OnLoadMoreAsync(IntersectionObserverEntry entry)
4343
if (entry.IsIntersecting)
4444
{
4545
await Task.Delay(1000);
46-
_items.AddRange(Enumerable.Range(_items.Count + 1, 20)
47-
.Select(i => $"https://picsum.photos/160/160?random={i}"));
46+
_items.AddRange(Enumerable.Range(_items.Count + 1, 20).Select(i => $"https://picsum.photos/160/160?random={i}"));
4847
StateHasChanged();
4948
}
5049
}
5150

51+
private bool _canLoading = true;
52+
private async Task OnLoadMoreItemAsync()
53+
{
54+
await Task.Delay(500);
55+
56+
_canLoading = _items.Count < 100;
57+
_items.AddRange(Enumerable.Range(_items.Count + 1, 20).Select(i => $"https://picsum.photos/160/160?random={i}"));
58+
StateHasChanged();
59+
}
60+
5261
private string? _videoStateString;
5362
private string? _textColorString = "text-muted";
5463

src/BootstrapBlazor.Server/Locales/en-US.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6855,7 +6855,10 @@
68556855
"AttributeAutoUnobserveWhenIntersection": "Whether to automatically cancel the observation when element visible",
68566856
"AttributeAutoUnobserveWhenNotIntersection": "Whether to automatically cancel the observation when element invisible",
68576857
"AttributeOnIntersectingAsync": "The callback when intersecting",
6858-
"AttributeChildContent": "Child component"
6858+
"AttributeChildContent": "Child component",
6859+
"LoadMoreTitle": "LoadMore Component",
6860+
"LoadMoreIntro": "By setting the <code>LoadMore</code> component parameter <code>IsLoading</code> to control the loading state, the <code>OnLoadMoreAsync</code> callback method loads more data",
6861+
"LoadMoreDesc": "In this example, the loading indicator is displayed by setting <code>CanLoading</code> to <code>true</code>, and the <b>No More Data</b> prompt text is displayed by setting it to <code>false</code> after loading is complete. The UI for loading more data can be customized through <code>LoadingTemplate</code>, the UI displayed when there is no more data can be customized through <code>NoMoreTemplate</code>, and the indicator text displayed when there are no more add-ons can be set through the <code>NoMoreText</code> parameter."
68596862
},
68606863
"BootstrapBlazor.Server.Components.Samples.SortableLists": {
68616864
"SortableListTitle": "SortableList",

src/BootstrapBlazor.Server/Locales/zh-CN.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6855,7 +6855,10 @@
68556855
"AttributeAutoUnobserveWhenIntersection": "元素可见时是否自动取消观察",
68566856
"AttributeAutoUnobserveWhenNotIntersection": "元素不可见时是否自动取消观察",
68576857
"AttributeOnIntersectingAsync": "可见回调方法",
6858-
"AttributeChildContent": "子组件"
6858+
"AttributeChildContent": "子组件",
6859+
"LoadMoreTitle": "LoadMore 组件",
6860+
"LoadMoreIntro": "通过设置 <code>LoadMore</code> 组件参数 <code>CanLoading</code> 控制加载状态,<code>OnLoadMoreAsync</code> 回调方法加载更多数据",
6861+
"LoadMoreDesc": "本例中通过设置 <code>CanLoading</code> 为 <code>true</code> 显示加载指示符,加载完成后设置为 <code>false</code> 显示 <b>没有更多数据</b> 提示文本,可以通过 <code>LoadingTemplate</code> 自定义加载更多的 UI,通过 <code>NoMoreTemplate</code> 自定义没有更多数据时显示的 UI,可以通过 <code>NoMoreText</code> 参数设置没有更多加载项时显示的指示文本"
68596862
},
68606863
"BootstrapBlazor.Server.Components.Samples.SortableLists": {
68616864
"SortableListTitle": "SortableList 拖拽组件",

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>9.8.2-beta01</Version>
4+
<Version>9.8.2-beta02</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Components/IntersectionObserver/IntersectionObserver.razor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
55

6-
76
namespace BootstrapBlazor.Components;
87

98
/// <summary>
@@ -12,7 +11,8 @@ namespace BootstrapBlazor.Components;
1211
public partial class IntersectionObserver
1312
{
1413
/// <summary>
15-
/// The element that is used as the viewport for checking visibility of the target. Must be the ancestor of the target. Defaults to the browser viewport if not specified or if null
14+
/// 获得/设置 是否使用元素视口作为根元素 默认为 false 使用浏览器视口作为根元素
15+
/// <para>The element that is used as the viewport for checking visibility of the target. Must be the ancestor of the target. Defaults to the browser viewport if value is false. Default value is false</para>
1616
/// </summary>
1717
[Parameter]
1818
public bool UseElementViewport { get; set; }

src/BootstrapBlazor/Components/IntersectionObserver/IntersectionObserver.razor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function init(id, invoke, options) {
88

99
const items = [...el.querySelectorAll(".bb-intersection-observer-item")];
1010

11-
if (options.useElementViewport === false) {
11+
if (options.useElementViewport === true) {
1212
options.root = el;
1313
}
1414
if (options.threshold && options.threshold.indexOf(' ') > 0) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@namespace BootstrapBlazor.Components
2+
@inherits BootstrapModuleComponentBase
3+
4+
<IntersectionObserver OnIntersecting="OnIntersecting" Threshold="@Threshold" AutoUnobserveWhenIntersection="false">
5+
<IntersectionObserverItem>
6+
<div class="bb-intersection-loading">
7+
@if (CanLoading)
8+
{
9+
if (LoadingTemplate != null)
10+
{
11+
@LoadingTemplate
12+
}
13+
else
14+
{
15+
<Spinner></Spinner>
16+
}
17+
}
18+
else if (NoMoreTemplate != null)
19+
{
20+
@NoMoreTemplate
21+
}
22+
else if (!string.IsNullOrEmpty(NoMoreText))
23+
{
24+
@NoMoreText
25+
}
26+
</div>
27+
</IntersectionObserverItem>
28+
</IntersectionObserver>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
5+
6+
using Microsoft.Extensions.Localization;
7+
8+
namespace BootstrapBlazor.Components;
9+
10+
/// <summary>
11+
/// 加载更多组件
12+
/// </summary>
13+
public partial class LoadMore
14+
{
15+
/// <summary>
16+
/// 获得/设置 触底元素触发 <see cref="OnLoadMoreAsync"/> 阈值 默认为 1
17+
/// </summary>
18+
[Parameter]
19+
public string Threshold { get; set; } = "1";
20+
21+
/// <summary>
22+
/// 获得/设置 触底回调方法 <see cref="CanLoading"/> 为 true 时才触发此回调方法
23+
/// </summary>
24+
[Parameter] public Func<Task>? OnLoadMoreAsync { get; set; }
25+
26+
/// <summary>
27+
/// 获得/设置 是否可以加载更多数据 默认为 true
28+
/// </summary>
29+
[Parameter]
30+
public bool CanLoading { get; set; } = true;
31+
32+
/// <summary>
33+
/// 获得/设置 加载更多模板 默认 null
34+
/// </summary>
35+
[Parameter]
36+
public RenderFragment? LoadingTemplate { get; set; }
37+
38+
/// <summary>
39+
/// 获得/设置 没有更多数据提示信息 默认为 null 读取资源文件中的预设值
40+
/// </summary>
41+
[Parameter]
42+
public string? NoMoreText { get; set; }
43+
44+
/// <summary>
45+
/// 获得/设置 没有更多数据时显示的模板 默认为 null
46+
/// </summary>
47+
[Parameter]
48+
public RenderFragment? NoMoreTemplate { get; set; }
49+
50+
[Inject, NotNull]
51+
private IStringLocalizer<LoadMore>? Localizer { get; set; }
52+
53+
/// <summary>
54+
/// <inheritdoc/>
55+
/// </summary>
56+
protected override void OnParametersSet()
57+
{
58+
base.OnParametersSet();
59+
60+
NoMoreText ??= Localizer[nameof(NoMoreText)];
61+
}
62+
63+
private async Task OnIntersecting(IntersectionObserverEntry entry)
64+
{
65+
if (entry.IsIntersecting && CanLoading && OnLoadMoreAsync != null)
66+
{
67+
await OnLoadMoreAsync();
68+
}
69+
}
70+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.bb-intersection-observer {
2+
--bb-intersection-observer-loading-bg: #{$bb-intersection-observer-loading-bg};
3+
--bb-intersection-observer-loading-color: #{$bb-intersection-observer-loading-color};
4+
--bb-intersection-observer-loading-padding: #{$bb-intersection-observer-loading-padding};
5+
6+
.bb-intersection-loading {
7+
display: flex;
8+
justify-content: center;
9+
align-items: center;
10+
background-color: var(--bb-intersection-observer-loading-bg);
11+
color: var(--bb-intersection-observer-loading-color);
12+
padding: var(--bb-intersection-observer-loading-padding)
13+
}
14+
}

0 commit comments

Comments
 (0)