Ce composant simple peut améliorer l’expérience utilisateur de votre application Blazor, en fournissant une indication qu’ils n’attendent pas en vain.
Créer des expériences fluides dans les applications Blazor pour une meilleure interaction devrait toujours être un point à considérer lors de leur développement.
L’une de ces expériences est le retour d’informations donné à l’utilisateur lorsque le traitement se déroule en coulisse, par exemple lorsque des informations sont récupérées pour remplir une page. L’un des composants qui peuvent nous aider dans cette tâche est l’interface utilisateur Progress Telerik pour Composant Blazor Skeletonqui vous permet de créer des espaces réservés de type chargeur dans les espaces où se trouveront les informations. Examinons ses fonctionnalités et comment l’intégrer dans une application Blazor.
Explorer le composant squelette pour Blazor
Commençons par analyser le fonctionnement du composant Skeleton. Tout d’abord, vous devez configurer le projet Blazor pour qu’il fonctionne avec les composants Telerik, selon le guides d’installation.
L’étape suivante consiste à vous rendre sur la page où vous souhaitez utiliser le composant, où vous pourrez l’ajouter via le TelerikSkeleton balise comme indiqué ci-dessous :
<div style="min-height:100vh; display:flex; align-items:center; justify-content:center;">
<div style="width:240px; height:48px;">
<TelerikSkeleton />
</div>
</div>
Dans le code ci-dessus, j’ai ajouté quelques styles pour centrer le composant sur la page, ce qui donne ce qui suit :
Maintenant, vous devez considérer que le composant possède les paramètres suivants que vous pouvez utiliser pour le configurer :
ShapeType(énumération) : Permet de sélectionner une forme prédéfinieAnimationType(énumération) : Permet de sélectionner une animation prédéfinieVisible(bouffon) : Spécifie si le composant doit être visible sur la page ou nonWidth(chaîne) etHeight(chaîne) : Spécifiez la largeur et la hauteur du composantClass(chaîne) : Permet le rendu d’une classe personnalisée dans le composant
A partir des propriétés précédentes, vous pouvez configurer ShapeType avec les valeurs SkeletonShapeType.Text (par défaut), SkeletonShapeType.Rectangle et SkeletonShapeType.Circleainsi que AnimationType avec les valeurs SkeletonAnimationType.None, SkeletonAnimationType.Pulse (par défaut) et SkeletonAnimationType.Wave.
Un exemple du composant Skeleton avec ces propriétés appliquées est le suivant :
<TelerikSkeleton
ShapeType="SkeletonShapeType.Circle"
AnimationType="SkeletonAnimationType.Pulse"
Width="100px" Height="100px" Visible="true">
</TelerikSkeleton>
Lors de la visualisation du composant, il se présente comme suit :
Bien que le contrôle soit assez simple à utiliser, sa puissance réside dans la combinaison de plusieurs de ces composants pour recréer des interfaces où l’on souhaite fournir un feedback à l’utilisateur sur un chargement d’informations, comme nous le verrons ensuite.
Ajout du composant squelette à un cas réel
Jusqu’à présent, nous avons vu les fonctionnalités du composant Skeleton. Maintenant, vous vous demandez peut-être comment l’intégrer dans votre application, c’est-à-dire comment créer une interface utilisant plusieurs composants Skeleton pendant le chargement des données, puis afficher les données réelles une fois chargées.
Pour rendre cela plus réaliste, supposons que nous ayons créé une application utilisant plusieurs composants Blazor qui simulent un réseau social. Voici la page d’accueil :
@page "/feed"
<div class="feed-container">
<h3 class="mb-3">Feed</h3>
<div class="composer card p-3 mb-4">
<div class="d-flex align-items-start gap-3">
<TelerikAvatar Type="AvatarType.Text" Width="48px" Height="48px" Rounded="@ThemeConstants.Avatar.Rounded.Full">HP</TelerikAvatar>
<div class="flex-grow-1">
<TelerikTextArea Rows="3" Placeholder="What's on your mind?" Width="100%" />
<div class="mt-2 d-flex gap-2 justify-content-end">
<TelerikButton ThemeColor="primary">
<TelerikSvgIcon Icon="@SvgIcon.PaperPlane"></TelerikSvgIcon> Post
</TelerikButton>
</div>
</div>
</div>
</div>
<div class="feed">
@foreach (var post in Posts)
{
<TelerikCard Class="mb-4">
<CardHeader>
<div class="d-flex align-items-center gap-3">
<TelerikAvatar Type="AvatarType.Text" Rounded="@ThemeConstants.Avatar.Rounded.Full" Width="48px" Height="48px">@GetInitials(post.UserName)</TelerikAvatar>
<div class="flex-grow-1 w-100">
<div class="fw-semibold">@post.UserName</div>
<div class="text-muted small">@post.PostedAt.ToLocalTime().ToString("g")</div>
</div>
</div>
</CardHeader>
<CardBody>
<p class="mb-3">@post.Content</p>
@if (!string.IsNullOrWhiteSpace(post.ImageUrl))
{
<img src="@post.ImageUrl" alt="post image" class="img-fluid rounded" />
}
</CardBody>
<CardFooter>
<div class="d-flex gap-2">
<TelerikButton ThemeColor="primary" FillMode="Telerik.Blazor.ThemeConstants.Button.FillMode.Outline">
<TelerikSvgIcon Icon="@SvgIcon.Heart"></TelerikSvgIcon> Like
</TelerikButton>
<TelerikButton FillMode="Telerik.Blazor.ThemeConstants.Button.FillMode.Outline">
<TelerikSvgIcon Icon="@SvgIcon.Comment"></TelerikSvgIcon> Comment
</TelerikButton>
<TelerikButton FillMode="Telerik.Blazor.ThemeConstants.Button.FillMode.Outline">
<TelerikSvgIcon Icon="@SvgIcon.Share"></TelerikSvgIcon> Share
</TelerikButton>
</div>
</CardFooter>
</TelerikCard>
}
</div>
</div>
@code {
private List<Post> Posts { get; set; } = new();
protected override async Task OnInitializedAsync()
{
await Task.Delay(5000);
LoadPosts();
}
private void LoadPosts()
{
Posts = new()
{
new Post
{
Id = Guid.NewGuid(),
UserName = "Bot Doe",
Content = "What a great day to try the Telerik UI for Blazor Skeleton. The UX feels great while data loads!",
ImageUrl = "https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?q=80&w=1200&auto=format&fit=crop",
PostedAt = DateTimeOffset.UtcNow.AddMinutes(-35)
},
new Post
{
Id = Guid.NewGuid(),
UserName = "Link",
Content = ".NET 10 migration done — everything feels snappier.",
ImageUrl = null,
PostedAt = DateTimeOffset.UtcNow.AddHours(-2)
},
new Post
{
Id = Guid.NewGuid(),
UserName = "Ada Lovelace",
Content = "Pro tip: leverage high-level components to speed up demos.",
ImageUrl = "https://images.unsplash.com/photo-1518837695005-2083093ee35b?q=80&w=1200&auto=format&fit=crop",
PostedAt = DateTimeOffset.UtcNow.AddDays(-1)
}
};
}
private static string GetInitials(string name)
{
if (string.IsNullOrWhiteSpace(name)) return "?";
var parts = name.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 1) return parts[0].Substring(0, Math.Min(1, parts[0].Length)).ToUpperInvariant();
return (parts[0][0].ToString() + parts[^1][0].ToString()).ToUpperInvariant();
}
private sealed class Post
{
public Guid Id { get; set; }
public string UserName { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public string? ImageUrl { get; set; }
public DateTimeOffset PostedAt { get; set; }
}
}
<style>
.feed-container {
max-width: 820px;
margin: 0 auto;
padding: 0 1rem;
}
.card {
box-shadow: var(--kendo-box-shadow, 0 1px 3px rgba(0,0,0,0.08));
border: 1px solid rgba(0,0,0,0.06);
border-radius: .5rem;
}
.composer .k-textarea {
width: 100%;
}
.feed img {
max-height: 420px;
object-fit: cover;
}
.gap-2 {
gap: .5rem;
}
.gap-3 {
gap: 1rem;
}
</style>
Si nous exécutons l’application maintenant, vous pouvez voir que nous avons une mauvaise expérience utilisateur, car elle ne fournit pas de retour indiquant qu’elle essaie de récupérer des informations pour remplir l’interface utilisateur, et vous devez attendre que le chargement soit terminé pour voir quelque chose à l’écran :
Résolvons ce problème en ajoutant le composant Skeleton. Ce que vous devez faire est d’essayer de créer une copie de l’interface graphique finale, mais en remplaçant chaque contrôle par le composant Skeleton dans une forme appropriée correspondant au composant final.
Par exemple, une forme circulaire peut être utilisée pour la photo de profil, une forme rectangulaire pour les photographies et laisser la forme par défaut pour le texte. Voici un exemple de ce remplacement dans l’en-tête du composant CardHeader:
Composant CardHeader avec les composants finaux rendus
<CardHeader>
<div class="d-flex align-items-center gap-3">
<TelerikAvatar Type="AvatarType.Text" Rounded="@ThemeConstants.Avatar.Rounded.Full" Width="48px" Height="48px">@GetInitials(post.UserName)</TelerikAvatar>
<div>
<div class="fw-semibold">@post.UserName</div>
<div class="text-muted small">@post.PostedAt.ToLocalTime().ToString("g")</div>
</div>
</div>
</CardHeader>
Composant CardHeader utiliser des composants TelerikSkeleton qui montrera l’effet de chargement
<CardHeader>
<div class="d-flex align-items-center gap-3">
<TelerikSkeleton ShapeType="SkeletonShapeType.Circle" Width="48px" Height="48px" />
<div class="flex-grow-1 w-100">
<TelerikSkeleton ShapeType="SkeletonShapeType.Text" Width="35%" Height="18px" Class="mb-1" />
<TelerikSkeleton ShapeType="SkeletonShapeType.Text" Width="20%" Height="14px" />
</div>
</div>
</CardHeader>
Dans le code précédent, je veux que vous remarquiez que chaque type d’élément a été remplacé par la forme appropriée du Squelette. Dans cet exemple précis, j’ai pu réutiliser les mêmes conteneurs div pour contenir les composants Skeleton, mais si vous en avez besoin, vous pouvez les modifier pour qu’ils fonctionnent mieux pour vous.
Suivant cette même logique, je vais créer et utiliser une propriété appelée IsLoading. Cette propriété me permettra de contrôler quand afficher et masquer les sections de chargement grâce à la création d’un if conditionnel. Dans ce conditionnel, nous pouvons valider si le chargement des informations est terminé, ce qui, s’il est positif, affichera les composants avec les informations comme suit :
@page "/feed"
<div class="feed-container">
<h3 class="mb-3">Feed</h3>
...
@if (IsLoading)
{
<div class="feed">
@for (int i = 0; i < 3; i++)
{
<TelerikCard Class="mb-4">
<CardHeader>
<div class="d-flex align-items-center gap-3">
<TelerikSkeleton ShapeType="SkeletonShapeType.Circle" Width="48px" Height="48px" />
<div class="flex-grow-1 w-100">
<TelerikSkeleton ShapeType="SkeletonShapeType.Text" Width="35%" Height="18px" Class="mb-1" />
<TelerikSkeleton ShapeType="SkeletonShapeType.Text" Width="20%" Height="14px" />
</div>
</div>
</CardHeader>
<CardBody>
<TelerikSkeleton ShapeType="SkeletonShapeType.Text" Width="100%" Height="14px" Class="mb-1" />
<TelerikSkeleton ShapeType="SkeletonShapeType.Text" Width="90%" Height="14px" Class="mb-1" />
<TelerikSkeleton ShapeType="SkeletonShapeType.Text" Width="80%" Height="14px" />
<TelerikSkeleton ShapeType="SkeletonShapeType.Rectangle" Width="100%" Height="220px" />
</CardBody>
<CardFooter>
<div class="d-flex gap-2">
<TelerikSkeleton ShapeType="SkeletonShapeType.Rectangle" Width="80px" Height="32px" />
<TelerikSkeleton ShapeType="SkeletonShapeType.Rectangle" Width="90px" Height="32px" />
</div>
</CardFooter>
</TelerikCard>
}
</div>
}
else
{
<div class="feed">
@foreach (var post in Posts)
{
<TelerikCard Class="mb-4">
<CardHeader>
<div class="d-flex align-items-center gap-3">
<TelerikAvatar Type="AvatarType.Text" Rounded="@ThemeConstants.Avatar.Rounded.Full" Width="48px" Height="48px">@GetInitials(post.UserName)</TelerikAvatar>
<div>
<div class="fw-semibold">@post.UserName</div>
<div class="text-muted small">@post.PostedAt.ToLocalTime().ToString("g")</div>
</div>
</div>
</CardHeader>
<CardBody>
<p class="mb-3">@post.Content</p>
@if (!string.IsNullOrWhiteSpace(post.ImageUrl))
{
<img src="@post.ImageUrl" alt="post image" class="img-fluid rounded" />
}
</CardBody>
<CardFooter>
<div class="d-flex gap-2">
<TelerikButton ThemeColor="primary" FillMode="Telerik.Blazor.ThemeConstants.Button.FillMode.Outline">
<TelerikSvgIcon Icon="@SvgIcon.Heart"></TelerikSvgIcon> Like
</TelerikButton>
<TelerikButton FillMode="Telerik.Blazor.ThemeConstants.Button.FillMode.Outline">
<TelerikSvgIcon Icon="@SvgIcon.Comment"></TelerikSvgIcon> Comment
</TelerikButton>
<TelerikButton FillMode="Telerik.Blazor.ThemeConstants.Button.FillMode.Outline">
<TelerikSvgIcon Icon="@SvgIcon.Share"></TelerikSvgIcon> Share
</TelerikButton>
</div>
</CardFooter>
</TelerikCard>
}
</div>
}
</div>
@code {
private bool IsLoading { get; set; } = true;
...
protected override async Task OnInitializedAsync()
{
...
IsLoading = false;
}
}
Dans le code précédent, vous pouvez voir qu’une fois le chargement des informations dans la méthode OnInitializedAsync est terminé, la valeur false est assigné à IsLoadingce qui provoque le rendu des contrôles avec les informations finales. Notez également que lors de l’affichage de l’interface à l’aide des composants Skeleton, seuls trois éléments sont affichés. Le résultat de l’exécution est le suivant :
Avec cela, vous avez pu constater comment le chargement des données dans l’interface graphique a été incroyablement amélioré.
Conclusion
Dans cet article, vous avez pu apprendre ce qu’est le contrôle Skeleton pour Blazor de Telerik et comment l’utiliser, ce qui est très utile pour fournir un feedback à l’utilisateur sur un processus qui implique l’obtention d’informations à afficher dans l’interface graphique. Vous avez vu ses différentes options de configuration, ainsi qu’un exemple dans une application Blazor où nous avons implémenté le composant.
C’est maintenant à votre tour d’améliorer l’expérience utilisateur dans vos applications en implémentant le composant Skeleton.
Le tout Interface utilisateur Telerik pour la bibliothèque d’interface utilisateur Blazor est disponible pour tester dans le cadre d’un essai gratuit de 30 jours.
Source link
