Le secret d’une interface utilisateur Blazor évolutive

Même si vous démarrez votre interface utilisateur au même endroit, voici comment la diviser en éléments de base pour un code Blazor propre et évolutif.
Si vous venez de MVC ou de Razor Pages, vous pourriez être tenté de traiter vos composants Razor (dans une application Blazor) comme des pages. Si tel est le cas, vous vous retrouverez probablement avec quelques gros composants, avec beaucoup d’interface utilisateur et de logique d’interface utilisateur en un seul endroit.
Mais si vous le faites, vous manquez une grande partie du potentiel de Blazor. Blazor (et d’autres frameworks basés sur des composants) prennent tout leur sens lorsque vous divisez votre interface utilisateur en morceaux plus petits et que vous les composez ensemble pour former des fonctionnalités plus grandes. Voici comment diviser votre interface utilisateur en ces éléments de base plus petits.
Commencez avec l’interface utilisateur en un seul endroit
Cela pourrait en fait avoir du sens commencer avec l’interface utilisateur dans un seul composant. Si vous essayez de recréer une conception/une maquette ou simplement d’innover sur une nouvelle fonctionnalité, il est plus facile de lancer HTML et CSS lorsque tout est au même endroit.
Vous pouvez rapidement parcourir l’interface utilisateur, modifier son apparence et utiliser du texte factice/des données codées en dur pour que quelque chose soit opérationnel dans le navigateur.
Mais ensuite, à mesure que votre fonctionnalité prend forme, il est utile de commencer à la décomposer en morceaux plus petits.
Blocs de construction
Prenons cet exemple d’une page produit simple pour une boutique en ligne.
À ce stade, cela est assez gérable. Mais disons que nous devons créer une nouvelle page « liste de souhaits », qui montre les produits spécifiques qu’un client a mis en favoris/ajoutés à une liste de souhaits.
Nous pourrions simplement copier et coller le balisage dans une nouvelle page, nous émerveiller de notre succès et mettre fin à cela…
Mais maintenant, nous accumulons des ennuis.
À mesure que de nouvelles exigences émergent ou que nous devons modifier l’apparence des fiches produits, nous devrons penser à mettre à jour le code à deux endroits.
C’est le moment idéal pour faire une refactorisation.
Si nous extrayons l’interface utilisateur de la fiche produit dans son propre composant, nous pouvons l’utiliser dans les deux pages.
ProductCard.razor
<div class="card">
<img class="card-img-top" src="@Product.Image" alt="Product Image Description"/>
<div class="card-body">
<h5 class="card-title">@Product.Title</h5>
<p class="card-text">@Product.Price.ToString("C")</p>
</div>
<div class="card-footer">
<p class="text-center">FREE Delivery</p>
</div>
</div>
@code {
[Parameter]
public ProductSummary Product { get; set; }
}
Désormais, chaque page peut restituer des instances de ceci ProductCard
composant au lieu de le dupliquer à chaque fois.
Liste de souhaits.razor
@page "/Wishlist"
<section class="container my-4">
<h2>Your Wishlist</h2>
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mt-2">
@foreach (var product in products)
{
<div class="col">
<ProductCard Product="@product"/>
</div>
}
</div>
</section>
@code {
private List<ProductSummary> products;
protected override Task OnInitializedAsync()
{
products = ProductStore.GetWishlist();
return base.OnInitializedAsync();
}
}
Mais disons que nous voulons aller plus loin.
Blocs de construction réutilisables
Une nouvelle exigence apparaît et nous réalisons que nous voulons le même style d’interface utilisateur de carte, mais pour quelque chose qui n’est pas réellement un produit. Nous aimons l’interface utilisateur de la carte et souhaitons la réutiliser, mais nous parlons maintenant d’un cas d’utilisation totalement différent.
Notre ProductCard
est actuellement câblé pour gérer les produits (il prend les détails du produit comme paramètre). Alors comment le réutiliser dans un tout autre contexte ?
La réponse est de prendre le balisage de l’interface utilisateur de la carte du ProductCard
UI et extrayez-le dans son propre Card
composant.
Carte.rasoir
<div class="card" style="width: 18rem;">
<img class="card-img-top" src="@ImageUrl" alt="Product Image Description"/>
<div class="card-body">
<h5 class="card-title">@Title</h5>
<p class="card-text">@Text</p>
</div>
<div class="card-footer text-center">
@FooterContent
</div>
</div>
@code {
[Parameter] public string ImageUrl { get; set; }
[Parameter] public string ImageAltText { get; set; }
[Parameter] public string Title { get; set; }
[Parameter] public string Text { get; set; }
[Parameter] public RenderFragment FooterContent { get; set; }
}
Nous créons essentiellement un Card
abstraction, nous pouvons donc lui donner les paramètres qui ont du sens pour une carte générique réutilisable.
Remarquez comment nous sommes passés du spécifique au plus général ici.
Liste des produits > Fiche produit > Carte
et…
Liste de souhaits > Fiche produit > Carte.
Sur le côté gauche, ces composants (et/ou pages) sont très spécifiques, liés à la logique métier pour une partie de notre domaine.
Mais à mesure que nous descendons dans l’arborescence des composants (à droite), nous arrivons à des composants moins spécifiques/plus généraux (et donc réutilisables).
Cette utilisation de la composition (composer des composants ensemble pour former des entités plus grandes) présente de nombreux avantages :
- Des composants plus petits sur lesquels raisonner
- État autonome (chaque instance d’un composant est uniquement concernée par son propre état)
- Les composants peuvent être réutilisés dans différentes parties de l’interface utilisateur
- Les composants n’ont pas nécessairement besoin d’être restitués lorsque leur parent le fait (sauf si leur propre état et/ou paramètres ont changé)
Voici la version finale de notre liste de produits, complétée par le ProductCard
et Card
Composants.
3 conseils pour créer efficacement votre interface utilisateur à l’aide de blocs de construction de composants
Voici quelques conseils pour diviser votre interface utilisateur en morceaux plus petits.
Utiliser des fragments de rendu pour restituer du contenu arbitraire
Dans le Card
composant, nous avons déclaré un RenderFragment
paramètre appelé FooterContent
.
Les fragments de rendu sont particulièrement utiles car ils vous permettent de transmettre n’importe quel contenu arbitraire à ce paramètre et de le rendre là où vous le souhaitez dans le balisage de la carte.
Vous pouvez spécifier plusieurs RenderFragment
paramètres et fournir du contenu pour certains/tous lors de la déclaration des instances du composant.
Gardez les composants réutilisables réutilisables
Essayez d’éviter de restreindre accidentellement l’endroit où un composant peut être utilisé.
Par exemple, si l’élément HTML racine de l’un de vos composants est un li
élément, alors vous ne pouvez techniquement utiliser ce composant qu’à l’intérieur d’une liste (ul
ou ol
). Il vaudrait peut-être mieux garder le li
dans le composant parent et placez tout ce qui se trouve en dessous dans votre composant.
Nous l’avons fait avec le ProductCard
élément lorsque nous avons évité la tentation de ramener le div
avec le col
classe dans le ProductCard
composant lui-même.
<div class="col">
<ProductCard Product="@product"/>
</div>
Cela maintient notre ProductCard
agréable et flexible, car il peut aller pratiquement n’importe où dans notre balisage.
Créer des versions spécialisées de composants
Si vous êtes tenté de modifier un composant (par exemple pour introduire un nouveau comportement), envisagez plutôt de créer un composant plus spécialisé qui délègue au composant d’origine.
Par exemple, disons que nous avons un simple Button
composant.
Bouton.rasoir
<button @onclick="OnClick" class="btn @Class">
@ChildContent
</button>
@code {
[Parameter] public EventCallback OnClick { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public string Class { get; set; }
}
Nous pouvons utiliser ce bouton où bon nous semble, en fournissant nos propres classes CSS, le cas échéant. En voici un exemple en action.
Supposons maintenant que nous ayons besoin d’un bouton qui affiche une confirmation lorsqu’on clique dessus, par exemple dans le cas d’une opération de suppression, nous voulons vérifier que l’utilisateur souhaite vraiment continuer.
Nous pourrions modifier Button
pour gérer cette exigence, mais il fait déjà un travail – et le fait efficacement !
L’alternative est d’envelopper Button
dans un nouveau ButtonDanger
composant.
ButtonDanger.razor
<Button Class="btn-danger" OnClick="PromptForConfirmation">
@ChildContent
</Button>
@code {
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public EventCallback OnClick { get; set; }
private void PromptForConfirmation(){
if(ShowConfirmationDialog == true){
OnClick.InvokeAsync();
}
}
}
Ici, nous interceptons le @OnClick
événement et afficher une boîte de dialogue de confirmation.
Si le résultat de l’affichage de cette boîte de dialogue est true
(l’utilisateur a confirmé qu’il pouvait continuer), nous pouvons invoquer l’original OnClick
méthode.
Voici comment nous utiliserions ce nouveau ButtonDanger
composant:
Accueil.rasoir
<ButtonDanger OnClick="ButtonClicked">
Delete Everything
</ButtonDanger>
@code {
void ButtonClicked(){
}
}
Et voici un exemple simple dans lequel nous affichons l’interface utilisateur de confirmation directement dans le ButtonDanger
composant lui-même.
Remarquez que nous n’avons apporté aucune modification au sous-jacent Button
composant pour prendre en charge cette nouvelle exigence relative aux « boutons dangereux ».
Cela permet de garder le bouton d’origine petit et ciblé, de sorte qu’il n’est pas pollué par une logique conditionnelle (pour déterminer quand une boîte de dialogue de confirmation doit ou ne doit pas être affichée).
En résumé : composez votre interface utilisateur à partir de petits éléments de base
Lors de la création de votre interface utilisateur, essayez de refactoriser vers des composants plus petits et ciblés. Les composants sont à leur meilleur (et les plus faciles à comprendre) lorsqu’ils font bien une chose.
Plutôt que de modifier les composants existants, envisagez de les envelopper dans des versions plus spécialisées qui ajoutent un comportement/une logique supplémentaire.
De cette façon, vous pouvez bénéficier de tous les avantages de la constitution d’une banque de composants réutilisables à mesure que votre interface utilisateur grandit et évolue.
Source link