Skip to content
This repository was archived by the owner on Jan 5, 2024. It is now read-only.

Commit efaf0a2

Browse files
authored
[新增] Skeleton 骨架屏组件 (#161)
2 parents b4e44f5 + bd15ee4 commit efaf0a2

4 files changed

Lines changed: 374 additions & 0 deletions

File tree

doc/TDesign.Docs.Shared/Layouts/NavMenu.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<TMenuItem Link="components/table">Table 表格</TMenuItem>
4545
<TMenuItem Link="components/tag">Tag 标签</TMenuItem>
4646
<TMenuItem Link="components/progress">Progress 进度条</TMenuItem>
47+
<TMenuItem Link="components/skeleton">Skeleton 骨架屏</TMenuItem>
4748

4849
</TMenuItemGroup>
4950
<TMenuItemGroup Title="消息提醒">
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
@page "/components/skeleton"
2+
3+
<PageHeader Title="Skeleton 骨架屏">
4+
当网络较慢时,在页面真实数据加载之前,给用户展示出页面的大致结构。
5+
</PageHeader>
6+
<HighlightAlert />
7+
<Example Title="基础骨架屏">
8+
<Description>最简单的骨架屏效果。</Description>
9+
<RunContent>
10+
<TSwitch @bind-Value="Loading" />
11+
<br />
12+
<TSkeleton Loading="Loading">
13+
骨架屏组件,是指当网络较慢时,在页面真实数据加载之前,给用户展示出页面的大致结构。 一方面让用户对页面有一定的心理预期,另一方面可以改善长期停留在空白屏给用户带来的枯燥和不适感。它可以为用户提供更好视觉效果和使用体验。
14+
</TSkeleton>
15+
</RunContent>
16+
<CodeContent>
17+
@Code.Create(@"
18+
```html
19+
<TSkeleton Loading=""Loading"">
20+
骨架屏组件,是指当网络较慢时,在页面真实数据加载之前,给用户展示出页面的大致结构。 一方面让用户对页面有一定的心理预期,另一方面可以改善长期停留在空白屏给用户带来的枯燥和不适感。它可以为用户提供更好视觉效果和使用体验。
21+
</TSkeleton>
22+
```
23+
")
24+
</CodeContent>
25+
</Example>
26+
27+
@code {
28+
bool Loading { get; set; }
29+
}
30+
<Example Title="带动画效果的骨架屏">
31+
<Description>提供渐变和闪烁两种动画效果。</Description>
32+
<RunContent>
33+
<TSkeleton Loading Animation="SkeletonAnimation.Gradient">
34+
35+
骨架屏组件,是指当网络较慢时,在页面真实数据加载之前,给用户展示出页面的大致结构。 一方面让用户对页面有一定的心理预期,另一方面可以改善长期停留在空白屏给用户带来的枯燥和不适感。它可以为用户提供更好视觉效果和使用体验。
36+
骨架屏组件,是指当网络较慢时,在页面真实数据加载之前,给用户展示出页面的大致结构。 一方面让用户对页面有一定的心理预期,另一方面可以改善长期停留在空白屏给用户带来的枯燥和不适感。它可以为用户提供更好视觉效果和使用体验。
37+
</TSkeleton>
38+
<br/>
39+
<TSkeleton Loading Animation="SkeletonAnimation.Flashed">
40+
41+
骨架屏组件,是指当网络较慢时,在页面真实数据加载之前,给用户展示出页面的大致结构。 一方面让用户对页面有一定的心理预期,另一方面可以改善长期停留在空白屏给用户带来的枯燥和不适感。它可以为用户提供更好视觉效果和使用体验。
42+
骨架屏组件,是指当网络较慢时,在页面真实数据加载之前,给用户展示出页面的大致结构。 一方面让用户对页面有一定的心理预期,另一方面可以改善长期停留在空白屏给用户带来的枯燥和不适感。它可以为用户提供更好视觉效果和使用体验。
43+
</TSkeleton>
44+
45+
</RunContent>
46+
<CodeContent>
47+
@Code.Create(@"
48+
```html
49+
<TSkeleton Animation=""SkeletonAnimation.Gradient""/>
50+
51+
<TSkeleton Animation=""SkeletonAnimation.Flashed""/>
52+
```
53+
")
54+
</CodeContent>
55+
</Example>
56+
<Example Title="不同主题的骨架屏">
57+
<Description>可以通过 <code>Theme</code> 参数快速定义不同主题风格的骨架屏。</Description>
58+
<RunContent>
59+
<p>文本</p>
60+
<TSkeleton Loading Theme="SkeletonTheme.Text"/>
61+
<br/>
62+
<p>段落</p>
63+
<TSkeleton Loading Theme="SkeletonTheme.Paragraph" />
64+
<br />
65+
<p>头像</p>
66+
<TSkeleton Loading Theme="SkeletonTheme.Avatar"/>
67+
<br/>
68+
<p>头像描述</p>
69+
<TSkeleton Loading Theme="SkeletonTheme.AvatarText"/>
70+
<br/>
71+
<p>选项卡</p>
72+
<TSkeleton Loading Theme="SkeletonTheme.Tab"/>
73+
<br/>
74+
<p>文章</p>
75+
<TSkeleton Loading Theme="SkeletonTheme.Article"/>
76+
</RunContent>
77+
<CodeContent>
78+
@Code.Create(@"
79+
```html
80+
<p>文本</p>
81+
<TSkeleton Loading Theme=""SkeletonTheme.Text""/>
82+
83+
<p>段落</p>
84+
<TSkeleton Loading Theme=""SkeletonTheme.Paragraph"" />
85+
86+
<p>头像</p>
87+
<TSkeleton Loading Theme=""SkeletonTheme.Avatar""/>
88+
89+
<p>头像描述</p>
90+
<TSkeleton Loading Theme=""SkeletonTheme.AvatarText""/>
91+
92+
<p>选项卡</p>
93+
<TSkeleton Loading Theme=""SkeletonTheme.Tab""/>
94+
95+
<p>文章</p>
96+
<TSkeleton Loading Theme=""SkeletonTheme.Article""/>
97+
```
98+
")
99+
</CodeContent>
100+
</Example>
101+
<Example Title="自定义骨架屏内容">
102+
<Description>显示地设置 <code>LoadingContent</code> 自己定义骨架屏的布局,并显示地设置 <code>ChildContent</code> 加载完后的内容。</Description>
103+
<RunContent>
104+
<TSwitch @bind-Value="Loading"/>
105+
<br />
106+
<TSkeleton Loading="Loading">
107+
<LoadingContent>
108+
<TSkeletonRow>
109+
<TSkeletonColumn/>
110+
<TSkeletonColumn Type="SkeletonColumnType.Circle"/>
111+
</TSkeletonRow>
112+
<TSkeletonRow>
113+
<TSkeletonColumn />
114+
<TSkeletonColumn Type="SkeletonColumnType.Circle" />
115+
<TSkeletonColumn />
116+
</TSkeletonRow>
117+
<TSkeletonRow>
118+
<TSkeletonColumn Type="SkeletonColumnType.Rectangle" style="width:100%"/>
119+
</TSkeletonRow>
120+
</LoadingContent>
121+
<ChildContent>
122+
这里是要显示的内容。
123+
</ChildContent>
124+
</TSkeleton>
125+
</RunContent>
126+
<CodeContent>
127+
@Code.Create(@"
128+
```html
129+
<TSkeleton Loading=""Loading"">
130+
<LoadingContent>
131+
<TSkeletonRow>
132+
<TSkeletonColumn/>
133+
<TSkeletonColumn Type=""SkeletonColumnType.Circle""/>
134+
</TSkeletonRow>
135+
<TSkeletonRow>
136+
<TSkeletonColumn />
137+
<TSkeletonColumn Type=""SkeletonColumnType.Circle"" />
138+
<TSkeletonColumn />
139+
</TSkeletonRow>
140+
<TSkeletonRow>
141+
<TSkeletonColumn Type=""SkeletonColumnType.Rectangle"" style=""width:100%""/>
142+
</TSkeletonRow>
143+
</LoadingContent>
144+
<ChildContent>
145+
这里是要显示的内容。
146+
</ChildContent>
147+
</TSkeleton>
148+
```
149+
")
150+
</CodeContent>
151+
</Example>

readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
## 🌈 在线示例
2626
[https://achievedowner.github.io/TDesignBlazor/](https://achievedowner.github.io/TDesignBlazor/)
2727

28+
> 由于网络问题,可能导致以上链接不可用,请下载源码并运行 `TDesign.Docs.ServerSide``TDesign.Docs.WebAssembly` 项目。
29+
2830
## 🖥 支持环境
2931

3032
- ![.NET 6](https://img.shields.io/badge/.NET-v6.0-green)
@@ -83,6 +85,7 @@
8385
## :pencil: 参与贡献
8486
* 如果你有意向参与贡献,请先阅读[贡献指南](./Contributing.md)
8587
* 有任何问题,欢迎通过 [Github issues](https://github.com/AchievedOwner/TDesignBlazor/issues) 反馈
88+
* 提供目前进度的实时[看板](https://github.com/users/AchievedOwner/projects/4)
8689
8790
**我们的贡献者**
8891
非常感谢每一个项目贡献者的辛勤付出
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
using Microsoft.AspNetCore.Components.Rendering;
2+
3+
namespace TDesign;
4+
/// <summary>
5+
/// 骨架屏。当网络较慢时,在页面真实数据加载之前,给用户展示出页面的大致结构。
6+
/// </summary>
7+
[ParentComponent]
8+
[CssClass("t-skeleton")]
9+
public class TSkeleton : BlazorComponentBase, IHasChildContent
10+
{
11+
/// <summary>
12+
/// 设置是否显示骨架屏。
13+
/// </summary>
14+
[Parameter][EditorRequired] public bool Loading { get; set; }
15+
/// <summary>
16+
/// 当 <see cref="Loading"/> 是 <c>false</c> 时显示的内容。
17+
/// </summary>
18+
[Parameter] public RenderFragment? ChildContent { get; set; }
19+
/// <summary>
20+
/// 当 <see cref="Loading"/> 是 <c>true</c> 时显示的内容。
21+
/// </summary>
22+
[Parameter] public RenderFragment? LoadingContent { get; set; }
23+
24+
/// <summary>
25+
/// 设置动画效果。
26+
/// </summary>
27+
[Parameter] public SkeletonAnimation? Animation { get; set; }
28+
29+
30+
/// <summary>
31+
/// 设置骨架屏的模式。可以快速设置骨架屏显示的模式。
32+
/// </summary>
33+
[Parameter] public SkeletonTheme? Theme { get; set; } = SkeletonTheme.Paragraph;
34+
35+
/// <inheritdoc/>
36+
protected override void OnParametersSet()
37+
{
38+
base.OnParametersSet();
39+
40+
if (Theme is not null && LoadingContent is null)
41+
{
42+
LoadingContent = GetThemeContent();
43+
}
44+
}
45+
46+
/// <inheritdoc/>
47+
protected override void AddContent(RenderTreeBuilder builder, int sequence)
48+
{
49+
if (Loading)
50+
{
51+
builder.AddContent(sequence, LoadingContent);
52+
}
53+
else
54+
{
55+
base.AddContent(builder, sequence);
56+
}
57+
}
58+
59+
/// <summary>
60+
/// 获取主题对应的骨架屏。
61+
/// </summary>
62+
RenderFragment GetThemeContent()
63+
=> Theme switch
64+
{
65+
SkeletonTheme.Text => builder => builder.CreateComponent<TSkeletonRow>(0, col => col.CreateComponent<TSkeletonColumn>(0)),
66+
SkeletonTheme.Paragraph => builder =>
67+
{
68+
builder.CreateComponent<TSkeletonRow>(0, col => col.CreateComponent<TSkeletonColumn>(0));
69+
builder.CreateComponent<TSkeletonRow>(1, col => col.CreateComponent<TSkeletonColumn>(0));
70+
builder.CreateComponent<TSkeletonRow>(2, col => col.CreateComponent<TSkeletonColumn>(0));
71+
}
72+
,
73+
SkeletonTheme.Avatar => builder => builder.CreateComponent<TSkeletonRow>(0, col => col.CreateComponent<TSkeletonColumn>(0, attributes: new { Type = SkeletonColumnType.Circle, style = "height:56px;width:56px" })),
74+
SkeletonTheme.AvatarText => builder => builder.CreateComponent<TSkeletonRow>(0, col =>
75+
{
76+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { Type = SkeletonColumnType.Circle });
77+
col.CreateComponent<TSkeletonColumn>(1, attributes: new { style = "height:32px" });
78+
}),
79+
SkeletonTheme.Tab => builder =>
80+
{
81+
builder.CreateComponent<TSkeletonRow>(0, col => col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" }));
82+
builder.CreateComponent<TSkeletonRow>(0, col => col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:200px" }));
83+
}
84+
,
85+
SkeletonTheme.Article => builder =>
86+
{
87+
builder.CreateComponent<TSkeletonRow>(0, col => col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "width:100%;height:30px" }));
88+
builder.CreateComponent<TSkeletonRow>(0, col => col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "width:100%;height:200px" }));
89+
90+
builder.CreateComponent<TSkeletonRow>(0, col =>
91+
{
92+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
93+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
94+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
95+
});
96+
97+
builder.CreateComponent<TSkeletonRow>(0, col =>
98+
{
99+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
100+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
101+
});
102+
103+
builder.CreateComponent<TSkeletonRow>(0, col =>
104+
{
105+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
106+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
107+
});
108+
109+
builder.CreateComponent<TSkeletonRow>(0, col =>
110+
{
111+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
112+
col.CreateComponent<TSkeletonColumn>(0, attributes: new { style = "height:30px" });
113+
});
114+
}
115+
,
116+
_ => builder => { }
117+
};
118+
}
119+
/// <summary>
120+
/// 表示骨架屏中的行。
121+
/// </summary>
122+
[ChildComponent(typeof(TSkeleton))]
123+
[ParentComponent]
124+
[CssClass("t-skeleton__row")]
125+
public class TSkeletonRow : BlazorComponentBase, IHasChildContent
126+
{
127+
128+
/// <inheritdoc/>
129+
[Parameter] public RenderFragment? ChildContent { get; set; }
130+
131+
}
132+
133+
/// <summary>
134+
/// 表示骨架屏中的行。
135+
/// </summary>
136+
[ChildComponent(typeof(TSkeleton))]
137+
[ChildComponent(typeof(TSkeletonRow))]
138+
[CssClass("t-skeleton__col")]
139+
public class TSkeletonColumn : BlazorComponentBase
140+
{
141+
142+
/// <summary>
143+
/// 获取 <see cref="TSkeleton"/> 组件。
144+
/// </summary>
145+
[CascadingParameter] public TSkeleton? CascadingSkeleton { get; set; }
146+
147+
/// <summary>
148+
/// 设置列的类型。
149+
/// </summary>
150+
[Parameter][CssClass("t-skeleton--type-")] public SkeletonColumnType Type { get; set; } = SkeletonColumnType.Text;
151+
152+
/// <inheritdoc/>
153+
protected override void BuildCssClass(ICssClassBuilder builder)
154+
{
155+
builder.Append($"t-skeleton--animation-{CascadingSkeleton?.Animation?.GetCssClass()}", CascadingSkeleton?.Animation is not null);
156+
}
157+
}
158+
/// <summary>
159+
/// 骨架屏列的类型。
160+
/// </summary>
161+
public enum SkeletonColumnType
162+
{
163+
/// <summary>
164+
/// 长方形。
165+
/// </summary>
166+
[CssClass("rect")] Rectangle,
167+
/// <summary>
168+
/// 圆形。
169+
/// </summary>
170+
Circle,
171+
/// <summary>
172+
/// 文本。
173+
/// </summary>
174+
Text
175+
}
176+
/// <summary>
177+
/// 骨架屏的动画效果。
178+
/// </summary>
179+
public enum SkeletonAnimation
180+
{
181+
/// <summary>
182+
/// 渐变效果。
183+
/// </summary>
184+
Gradient,
185+
/// <summary>
186+
/// 闪烁效果。
187+
/// </summary>
188+
Flashed
189+
}
190+
/// <summary>
191+
/// 骨架屏主题模式。
192+
/// </summary>
193+
public enum SkeletonTheme
194+
{
195+
/// <summary>
196+
/// 文本。
197+
/// </summary>
198+
Text,
199+
/// <summary>
200+
/// 段落。
201+
/// </summary>
202+
Paragraph,
203+
/// <summary>
204+
/// 头像。
205+
/// </summary>
206+
Avatar,
207+
/// <summary>
208+
/// 头像文本。
209+
/// </summary>
210+
AvatarText,
211+
/// <summary>
212+
/// 选项卡。
213+
/// </summary>
214+
Tab,
215+
/// <summary>
216+
/// 长篇文章。
217+
/// </summary>
218+
Article
219+
}

0 commit comments

Comments
 (0)