web-dev-qa-db-fra.com

Comment animer les transitions d'état dans Blazor?

Dans mes composants Blazor, je rend souvent des composants basés sur une instruction conditionnelle, par exemple.

@if (_contact.IsCustomer)
{
    <SalesOrdersList Customer="@_contact" />
}

Ou à partir d'une boucle, par ex.

@foreach(var salesOrder in _customer.SalesOrders)
{
    <SalesOrderSummary SalesOrder="@salesOrder" />
}

Lorsque je change d'état, j'aimerais animer la transition d'état afin que les composants fade in/out. Dans les exemples ci-dessus, cela peut se produire lorsque IsCustomer change, ou lorsqu'un enregistrement est ajouté ou supprimé de la collection SalesOrders.

Animation de l'ajout d'un composant

Je peux voir comment cela peut être réalisé lors de l'ajout d'un composant, par le composant ayant une classe CSS qui a une animation en fondu qui se produit lorsque le composant est rendu - par exemple comme indiqué dans excellent exemple de pain grillé de Chris Sainty

Animation de la suppression d'un composant

Je ne peux pas penser comment vous feriez cela lorsque vous supprimez un composant, parce que le composant cesse simplement d'exister lorsque cette partie du DOM est restituée?

React a react-transition-group qui traite de la période de transition, mais je ne trouve rien de similaire dans Blazor pour l'instant?

Existe-t-il un moyen d'ajouter une animation pour la suppression d'un composant dans Blazor?

Animation des transitions de page

L'autre transition d'état souvent animée change les "pages". Encore une fois, je ne trouve pas de moyen de le faire dans Blazor pour le moment? En fait, cela peut simplement être une animation pour supprimer l'ancien composant de page et une autre pour ajouter le nouveau, mais dans certains cadres, cela se fait au niveau du routage plutôt qu'au niveau du composant - je ne trouve rien à aucun niveau dans Blazor pour le moment ?

8
tomRedox

Blazor ne couvre pas ce scénario, pour cela, vous devez utiliser CSS. Il est difficile de vous donner un exemple spécifique car cela dépend exactement de la façon dont vous souhaitez que vos animations fonctionnent et avec quel type de style, mais je vous suggère de vérifier les transitions CSS et les images clés.

Voici quelques bonnes ressources

Comme vous l'avez mentionné dans votre question, la gestion des éléments supprimés est quelque chose que je n'ai pas encore pu comprendre. Je ne peux donc pas m'en empêcher malheureusement.

4
Chris Sainty

Mise à jour: Plutôt que d'utiliser ce qui suit, j'ai mis une solution améliorée pour cela (ne repose pas sur Task.Delay) sur GitHub: https://github.com/dazinator/BlazorDeferredRemove

J'ai choisi l'approche suivante pour gérer la décoloration d'un élément avant qu'il ne soit supprimé par le blazor du DOM. C'est une solution de contournement qui utilise Task.Delay et le compromis est que parce que j'utilise Task.Delay avec un temps spécifié en millisecondes, ce temps doit s'aligner sur la durée que vous utilisez dans css pour la transition - sinon l'élément pourrait être supprimé par blazor avant (ou après) la transition:

Composant Transition.razor réutilisable:

    <div class="@(ToggleActive ? ToggleTransitionOnCssClassName: ToggleTransitionOffCssClassName)">
        @ChildContent;
    </div>

    @code {

    [Parameter] RenderFragment ChildContent { get; set; }

    [Parameter] string ToggleTransitionOnCssClassName { get; set; } = "";
    [Parameter] string ToggleTransitionOffCssClassName { get; set; } = "";

    [Parameter] int TransitionDurationMilliseconds { get; set; } = 200;

    public bool ToggleActive { get; set; }

    [Parameter] EventCallback<bool> TransitionEnded { get; set; }

    public async Task ToggleTransition()
    {
        ToggleActive = !ToggleActive;
        await Task.Delay(TransitionDurationMilliseconds);
        await TransitionEnded.InvokeAsync(ToggleActive);
    }


    }

et il est utilisé comme tel à partir d'une page ou d'un composant parent:

         @if (RenderThingy)
        {
            <Transition @ref="Transition" TransitionDurationMilliseconds="500" ToggleTransitionOnCssClassName="m-fadeOut" ToggleTransitionOffCssClassName="m-fadeIn" TransitionEnded="@TransitionComplete">
                <RenderThingy OnDismissed="@OnDismissed"></RenderThingy>
            </Transition>
        }

@code {

    Transition Transition { get; set; }
    bool RenderThingy {get; set;} = true;

    async Task OnDismissed()
    {
        await Transition.ToggleTransition();
    }
    private void TransitionComplete(bool toggleState)
    {
        RenderThingy = false;
    }
}

et css:

.m-fadeIn {
    visibility: visible;
    opacity: 1;
    animation: fadein 500ms;
}

@keyframes fadein {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

.m-fadeOut {
    animation: fadeout 500ms;
}

@keyframes fadeout {
    from {
        opacity: 1;
    }

    to {
        opacity: 0;       
    }
}
2
Darrell

Une solution de contournement

nous pouvons afficher/masquer en utilisant [~ # ~] css [~ # ~] . Assurez-vous simplement de gérer les paramètres null qui sont passés au composant lorsqu'il est masqué.

Disons que nous avons le composant Person comme ci-dessous:

<style>
.container{
    display:inline-block;
    width:@width;
    height:@height;
    color:white;
    background-color:blue;
}
.fade-out{ 
   animation: fade @AnimTime linear forwards;
}
.spin-in{
   animation: spin @AnimTime linear forwards;
}

@@keyframes fade {
  0%   {opacity:1;}
  99%  {width:@width; height:@height;}
  100% {width:0px;height:0px; opacity:0;}
}
@@keyframes spin {
  0%   {width:0px;height:0px; transform: rotate(0deg);}
  99%  {width:@width; height:@height;}
  100% {width:@width;height:@height;transform: rotate(1440deg);}
}
</style>
<div class="container @(IsShown?"spin-in":"fade-out")">
    <span>@(Name??"")</span>
</div>
@code {
    string width="100px";
    string height="20px";

    [Parameter]
    public string Name { get; set; }

    [Parameter]
    public string AnimTime { get; set; } 

    [Parameter]
    public bool IsShown {get; set;}
}

et nous l'utilisons dans une autre page/composant comme ci-dessous:

<button @onclick="(_=>{isShown=!isShown;})">Switch</button>
<span>Left hand of component</span>
<Person Name="Jack" AnimTime="2s" IsShown=@isShown/>
<span>Right hand of component</span>
@code{
    bool isShown=true;
}

J'ai utilisé @width, @height, @AnimTime les variables dans [~ # ~] css [~ # ~] pour montrer simplement les possibilités sont infinies. Je dois noter que keyframes dans le composant Blazor doit commencer par le symbole double at (@@).

Voir la démo en direct sur BlazorFiddle et html + CSS uniquement sur JSFiddle .

Une autre astuce

Dans le cas où l'utilisateur clique sur un bouton comme fermer ou [~ # ~] x [~ # ~] vous pouvez compresser une courte animation de 0,1 s ou 0,2 s pendant la période de souris vers le haut. La souris déclenche l'animation, mais la souris vers le haut supprime le composant. J'ai codé cela avant ici

1
Sorush

Pour le côté du retrait des composants:

J'ai ajouté une demande de fonctionnalité GitHub pour la suppression sur le référentiel AspNetCore. Steve Sanderson de Microsoft a souligné que l'animation de la suppression de composants devrait déjà être possible avec l'API exposée par le framework Blazor, mais il serait probablement avantageux que quelqu'un écrive un package pour le rendre plus simple à implémenter:

La solution que j'attendrais est de créer un composant d'animation qui rend soit une liste soit un seul élément, et intègre une logique pour retarder la suppression de chaque élément afin qu'il puisse être animé. Blazor a déjà de bonnes primitives pour les composants de modèles, donc les API résultantes devraient être plutôt sympas. Ce serait essentiellement la même solution que celle utilisée dans d'autres cadres SPA.

Ceci est réalisable dans le code utilisateur et ne nécessite pas de fonctionnalité de structure intégrée. Je ne dis pas que c'est facile, mais j'espère que quelqu'un dans la communauté trouvera le temps de le faire. C'est quelque chose que je peux faire moi-même à un moment donné, mais j'ai d'autres priorités à court terme.

dazinator /@Darrell a pris cela et a produit le paquet Blazor Deferred Remove Nuget pour le faire. Je n'ai pas encore essayé cela, mais cela ressemble à ce qui est nécessaire pour y parvenir.

Il y a maintenant aussi le paquet Blazor.Animate .

1
tomRedox