Site icon Blog ARC Optimizer

Principes de base de Blazor : création de fonctionnalités de glisser-déposer

Principes de base de Blazor : création de fonctionnalités de glisser-déposer


Découvrez comment implémenter la fonctionnalité glisser-déposer dans Blazor et comment Telerik UI pour Blazor rend la tâche encore plus simple pour les développeurs.

L’une des choses les plus importantes pour les applications Web modernes est l’expérience utilisateur et développeur. Avec Blazor, nous disposons d’un modèle de composant simple mais puissant. Pour de nombreuses applications, la fonctionnalité glisser-déposer est essentielle pour offrir une expérience utilisateur transparente.

Nous apprendrons comment implémenter la fonctionnalité glisser-déposer dans Blazor et comment l’interface utilisateur Progress Telerik pour Bibliothèque de composants Blazor rend la tâche encore plus simple pour les développeurs.

Tu peux accéder au code utilisé dans cet exemple sur GitHub.

Comprendre le glisser-déposer dans les applications Web

Les navigateurs modernes prennent en charge HTML5 et ses API glisser-déposer. Le glisser-déposer fonctionne en deux parties :

Tout d’abord, nous définissons certains éléments HTML comme déplaçablequi permet à l’utilisateur de les glisser et de les déposer dans des zones cibles appelées zones de largage.

Deuxièmement, JavaScript implémente la logique d’interaction nécessaire pour effectuer le glisser-déposer en arrière-plan, comme déplacer un employé d’une équipe à une autre.

Considérez l’exemple minimaliste de glisser-déposer suivant développé avec HTML5 et JavaScript :

Maintenant, parlons du code :

<div>
    <div draggable="true" id="emp1">Alice</div>
    <div draggable="true" id="emp2">Bob</div>
    <div draggable="true" id="emp3">Charlie</div>
</div>

<div>
    <h2>Team A</h2>
    <div class="dropzone" id="teamA"></div>
</div>

<div>
    <h2>Team B</h2>
    <div class="dropzone" id="teamB"></div>
</div>

Nous avons un div contenant différents salariés représentés à l’aide d’un autre div élément. Le draggable L’attribut définit un élément HTML qui peut être déplacé par l’utilisateur.

Contrairement au draggable attribut, les zones de dépôt sont régulières div éléments sans aucun attribut spécial appliqué. Dans ce cas, nous utilisons la classe dropzone pour identifier les zones de dépôt dans le code JavaScript, mais il existe d’autres solutions.

Nous pouvons désormais utiliser JavaScript pour gérer les événements DOM afin d’effectuer l’opération glisser-déposer et mettre à jour l’état de l’application :

const state = {
    employees: {
    emp1: { name: 'Alice', team: null },
    emp2: { name: 'Bob', team: null },
    emp3: { name: 'Charlie', team: null },
    },
};

const employees = document.querySelectorAll('.employee');
employees.forEach(employee => {
    employee.addEventListener('dragstart', e => {
    e.dataTransfer.setData('text/plain', employee.id);
    });
});

Pour le draggable éléments, nous devons ajouter auditeurs d’événements pour le dragstart événement et utilisez le dataTransfer propriété pour mettre en cache le employeeId.

const dropzones = document.querySelectorAll('.dropzone');
dropzones.forEach(zone => {
    zone.addEventListener('dragover', e => {
    e.preventDefault();
    });

    zone.addEventListener('drop', e => {
    e.preventDefault();
    const empId = e.dataTransfer.getData('text/plain');
    const employee = document.getElementById(empId);
    if (employee) {
        zone.appendChild(employee);

        
        const teamId = zone.id;
        state.employees[empId].team = teamId;
    }
    });
});

Pour les zones de dépôt, nous devons enregistrer un gestionnaire d’événements pour le dragover et empêche l’action par défaut (sinon le retrait ne fonctionne pas), ainsi que l’événement drop pour gérer un événement effectué. drop opération.

Encore une fois, nous utilisons le dataTransfer propriété pour accéder au cache employeeId et ajoutez l’employé div vers la zone de largage. Par la suite, nous mettons à jour l’état de l’application.

Le code affiché ne représente que les éléments essentiels. Tu peux accéder au fichier HTML de travail sur GitHub.

Limitations et bizarreries de l’API native de glisser-déposer

Dans l’exemple précédent, nous n’avons fait qu’effleurer la surface de l’API native HTML5 Drag-and-Drop.

Malheureusement, il existe des différences subtiles entre les différents navigateurs. Par exemple, Firefox nécessite une gestion supplémentaire pour certains types de fichiers, et certains appareils tactiles (notamment iOS) ne prennent pas entièrement en charge l’API native.

Une autre limitation est que nous devons utiliser des hacks JavaScript pour les éléments HTML qui ne prennent pas en charge le draggable attribut.

En outre, l’expérience utilisateur présente des défis, tels qu’un contrôle limité sur les animations et des ordres d’événements incohérents pour les utilisateurs. dragenter, dragover et dragleave événements.

La bibliothèque Telerik UI for Blazor fournit des composants, tels que le Composant Blazor ListBox avec prise en charge intégrée du glisser-déposer. Ces composants implémentent une cohérence entre navigateurs et une prise en charge intégrée des interactions tactiles. Vous pouvez même personnaliser les aperçus par glisser-déposer et contourner la limitation du déplacement.

Implémentation de base du glisser-déposer dans Blazor

Dans l’exemple précédent, vous avez pu constater qu’avec HTML5 et JavaScript, nous devons gérer divers événements sur différents éléments. Voyons maintenant comment gérer le glisser-déposer dans Blazor.

Indice: Avant de commencer, il est important de préciser qu’il existe plusieurs façons d’implémenter le glisser-déposer pour Blazor. La solution présentée ici est ma préférée.

Premièrement, Blazor n’a pas d’accès direct aux API du DOM et du navigateur. Nous devons donc utiliser Interopérabilité JavaScript lors de la mise en œuvre du glisser-déposer dans Blazor.

Du côté positif : L’implémentation fonctionne pour l’interactivité de Blazor Server et Blazor WebAssembly.

Tout d’abord, commençons par le Teams.razor déposer. C’est la page qui affiche les employés et permet à l’utilisateur de les affecter à une équipe spécifique.

@page "/teams"
@implements IDisposable
@inject IJSRuntime JS

<h3>Employees</h3>
<div class="column">
    @foreach (var emp in Employees.Where(e => e.Team is null))
    {
        <EmployeeItem @key="emp.Id" Employee="emp" />
    }
</div>

<h3>Team A</h3>
<div class="dropzone" @ref="teamARef">
    @foreach (var emp in Employees.Where(e => e.Team == "A"))
    {
        <EmployeeItem @key="emp.Id" Employee="emp" />
    }
</div>

<h3>Team B</h3>
<div class="dropzone" @ref="teamBRef">
    @foreach (var emp in Employees.Where(e => e.Team == "B"))
    {
        <EmployeeItem @key="emp.Id" Employee="emp" />
    }
</div>

Le code du modèle est simple.

Nous utilisons le @page directive pour enregistrer ce composant Razor en tant que page routable.

Ensuite, nous implémentons le IDisposable interface car nous travaillerons avec refs qui doivent être éliminés manuellement.

Nous injectons également une instance du IJSRuntime interface pour pouvoir appeler du code d’interopérabilité JavaScript à partir de notre composant de page.

Nous en avons trois divs. Le premier contient tous les employés, les deuxième et troisième sont des zones de dépôt pour l’équipe A et l’équipe B. Notez le @ref attribut sur les deux zones de dépôt.

Dans la section code, nous déclarons d’abord quelques propriétés et champs :

private List<Employee> Employees = new()
{
    new Employee { Id = "emp1", Name = "Alice" },
    new Employee { Id = "emp2", Name = "Bob" },
    new Employee { Id = "emp3", Name = "Charlie" }
};

private ElementReference teamARef;
private ElementReference teamBRef;

private DotNetObjectReference<Teams>? dotNetRef;

Nous avons une liste de trois employés. Le Employee la classe est définie dans un fichier séparé et ressemble à ceci :

public class Employee
{
    public string Id { get; set; } = "";
    public string Name { get; set; } = "";
    public string? Team { get; set; }
}

Nous avons aussi deux ElementReferences teamARef et teamBRef que nous lions à leurs zones de dépôt dans le code du modèle.

Nous avons également un exemple de DotNetObjectReference type, ce qui nous permet de boucler la boucle avec l’intégration JavaScript et de rappeler notre code .NET à partir du code JavaScript.

Ensuite, nous implémentons le OnAfterRenderAsync méthode, où nous enregistrons les zones de dépôt en utilisant l’interopérabilité JavaScript.

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        dotNetRef = DotNetObjectReference.Create(this);

        await JS.InvokeVoidAsync("dragDropInterop.registerDropZone", 
            teamARef, dotNetRef, "A");
        await JS.InvokeVoidAsync("dragDropInterop.registerDropZone", 
            teamBRef, dotNetRef, "B");
    }
}

Nous créons un DotNetObjectReference objecter et appeler le registerDropZone fonctions.

[JSInvokable]
public Task OnEmployeeDropped(string employeeId, string team)
{
    var emp = Employees.FirstOrDefault(e => e.Id == employeeId);
    if (emp is not null)
    {
        emp.Team = team;
        StateHasChanged();
    }
    return Task.CompletedTask;
}

public void Dispose()
{
    dotNetRef?.Dispose();
}

Ensuite, nous avons un OnEmployeeDropped méthode qui sera appelée depuis le code JavaScript lorsqu’une opération de glisser-déposer aura été effectuée par l’utilisateur. Remarquez le [JSInvokeable] attribut, qui est requis pour que la méthode soit appelée à partir du code JavaScript.

Et le Dispose méthode élimine correctement le dotNetRef objet.

Indice: Je ne montre pas les définitions CSS dans cet article, mais vous pouvez accéder au code complet sur GitHub.

Avant d’examiner le code d’interopérabilité JavaScript, explorons le EmployeeItem référencé dans le modèle du Teams composant de page.

<div @ref="elementRef" class="employee">
    @Employee.Name
</div>

@code {
    [Parameter] public Employee Employee { get; set; } = default!;
    [Inject] private IJSRuntime JS { get; set; } = default!;

    private ElementReference elementRef;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JS.InvokeVoidAsync(
                "dragDropInterop.addDragStartListener", 
                elementRef, 
                Employee.Id);
        }
    }
}

Le code du modèle est simple. Nous utilisons un div et attribuer un ElementReference s’opposer à son ref attribut.

Dans le OnAfterRenderAsync mise en œuvre, nous appelons le addDragStartListener fonction pour le premier rendu du composant et fournir l’ID de l’employé.

Maintenant, regardons enfin le code d’interopérabilité JavaScript qui maintient le tout ensemble et fait fonctionner le glisser-déposer :

Nous créons un nouveau dragDropInterop.js fichier à l’intérieur du wwwroot/js dossier:

window.dragDropInterop = {
    addDragStartListener: function (element, employeeId) {
        if (!element) return;
        element.setAttribute('draggable', 'true');
        element.addEventListener('dragstart', function (event) {
            event.dataTransfer.setData('text/plain', employeeId);
        });
    },

    registerDropZone: function (element, dotnetHelper, team) {
        if (!element) return;

        element.addEventListener('dragover', function (event) {
            event.preventDefault();
        });

        element.addEventListener('drop', function (event) {
            event.preventDefault();
            const draggedId = event.dataTransfer.getData('text/plain');
            if (draggedId) {
                dotnetHelper.invokeMethodAsync('OnEmployeeDropped', draggedId, team);
            }
        });
    }
};

Nous ajoutons deux fonctions au window objet.

Le addDragStartListener la fonction est appelée depuis le OnAfterRenderAsync méthode du cycle de vie lorsqu’un EmployeeItem est d’abord rendu.

Cette fonction ajoute dynamiquement le draggable attribut, indiquant au navigateur que l’utilisateur peut faire glisser cet élément HTML. Nous enregistrons également un écouteur d’événement pour le dragstart événement pour mettre en cache l’ID de l’employé, afin que nous sachions quel employé est déplacé.

Semblable à l’implémentation HTML et JavaScript pure, nous utilisons le dataTransfer la propriété et ses setData fonction.

Le registerDropZone la fonction est appelée depuis le OnAfterRenderAsync méthode sur le Teams composant de page lors du rendu pour la première fois.

Dans cette fonction, nous enregistrons un gestionnaire d’événements pour le dragover événement et appelez le preventDefault fonction. Encore une fois, c’est important pour que le glissement fonctionne.

Nous enregistrons également un écouteur d’événement pour le drop événement. Ici, en plus d’appeler également le preventDefault fonction, nous obtenons l’ID de l’employé déplacé et appelons la méthode .NET OnEmployeeDropped sur le Teams composant de page à l’aide du DotNetObjectReference nous avons reçu lorsque le registerDropZone la fonction a été appelée à partir du code .NET.

Important: N’oubliez pas d’ajouter une référence au dragDropInterop.js fichier dans le App.razor fichier pour charger le code JavaScript lorsque l’application s’exécute dans le navigateur :

<!DOCTYPE html>
<html lang="en">
<! -- code omitted -->
<body>
    <Routes @rendermode="InteractiveServer" />
    <script src="_framework/blazor.web.js"></script>
    <script src="js/dragDropInterop.js"></script>
</body>

</html>

Maintenant, exécutez votre application Blazor.

Accédez au Teams page (ajustez le code dans la NavMenu composant, ou ajouter /teams dans la barre d’adresse), et vous devriez pouvoir voir initialement les trois employés dans la liste des employés.

Vous pouvez les affecter à l’équipe A ou B et même changer d’équipe par glisser-déposer.

Principales différences entre le glisser-déposer natif et Blazor

Soulignons les différences entre le glisser-déposer Blazor et une implémentation native HTML5 et JavaScript.

Liaison d’objet offre un meilleur contrôle et un moyen plus simple de gérer l’état. Nous utilisons les propriétés C# et l’état de liaison au lieu des API HTML5 impératives.

Nous utilisons moins de code pour lier les événements aux méthodes C# au lieu d’ajouter des écouteurs d’événements à l’aide de l’API JavaScript impérative. Nous pouvons encapsuler le code JavaScript requis dans un interop.js et réutilisez-le pour plusieurs implémentations par glisser-déposer.

Dernier, débogage est beaucoup plus puissant en utilisant le débogueur C# complet et la sécurité des types que les journaux de la console ou les outils de développement du navigateur.

D’un autre côté, comme Blazor n’a pas d’accès direct aux événements DOM et à l’API Drag-and-Drop, nous devons utiliser l’interopérabilité JavaScript. Cependant, nous pourrions résumer ce comportement. C’est exactement ce que font les bibliothèques de composants, telles que Interface utilisateur Telerik pour Blazorfaire.

Conseils pour l’expérience utilisateur

Bien que le glisser-déposer soit une fonctionnalité moderne et généralement conviviale, tenez compte des trucs et astuces suivants :

  • Mettez en surbrillance les zones de dépôt. Il n’y a rien de pire pour un utilisateur que de ne pas comprendre où peut être placé l’objet en main. Par exemple, utilisez des bordures aux couleurs vives ou modifiez l’arrière-plan de la zone de dépôt une fois activée. Nous plaçons généralement le code dans le ondragenter et ondragover gestionnaires d’événements pour implémenter un tel comportement.
  • Validez les cibles de dépôt. Si les règles métier ne permettent pas de déplacer certains éléments vers certaines zones de dépôt, implémentez des vérifications conditionnelles dans vos gestionnaires de dépôt. Points bonus pour rendre les zones de dépôt non valides visibles à l’utilisateur, par exemple en ajoutant un invalid classe à l’élément HTML.

Conclusion

Le glisser-déposer fait partie intégrante des applications Web modernes. Dans les applications Web Blazor, nous utilisons l’interopérabilité JavaScript pour l’orchestrer.

Avec la liaison de données, nous obtenons un moyen simple de suivre et de restituer l’état de l’application lorsqu’une opération de glisser-déposer est effectuée.

Assurez-vous de suivre les meilleures pratiques, de valider correctement les cibles de dépôt et de mettre en évidence les zones de dépôt disponibles dans vos applications.

Tu peux accéder au code utilisé dans cet exemple sur GitHub.

Si vous souhaitez en savoir plus sur le développement de Blazor, vous pouvez regarder mon cours intensif Blazor gratuit sur YouTube. Et restez à l’écoute du blog Telerik pour en savoir plus Les bases du Blazor.


Essayez par vous-même l’interface utilisateur de Telerik pour les fonctionnalités de glisser-déposer de Blazor. La bibliothèque est livrée avec un essai gratuit de 30 jours.

Essayez l’interface utilisateur Telerik pour Blazor




Source link
Quitter la version mobile