Le drag and drop avec HTML5 et jQuery

Dernière mise à jour : juin 2014

Vous connaissez tous le drag and drop ?!

Pour rappel, c’est le fait de pouvoir glisser-déposer un élément vers – ou à la place – d’un autre.


C’est une technique plutôt complexe à mettre en oeuvre et bon nombre de développeurs Web cherchent des solutions légères et faciles à utiliser.

C’est ce que nous propose l’API Drag and Drop d’HTML5. En gros, les navigateurs récents (sauf IE) embarquent nativement le DnD.
On peut évidemment le mettre en place en Javascript pur, je vais plutôt vous montrer comment faire avec jQuery, autant en profiter s’il est déjà chargé dans la page n’est-ce pas ? Ici il n’est pas question d’utiliser le plugin DnD de jQuery UI.

Nous allons voir un système de liste que l’on pourra réordonner via du DnD. Ci-dessous un code HTML d’une liste, vous remarquerez un nouvel attribut draggable.
Vous l’aurez deviné, il sert à indiquer au navigateur que l’élément peut être « glissé ». Sans l’attribut à true il n’est pas la peine d’aller plus loin.

<ul id="liste">
  <li draggable="true">A</li>
  <li draggable="true">B</li>
  <li draggable="true">C</li>
  <li draggable="true">D</li>
</ul>

<div id="log"></div>

J’ai ajouté #log pour la démonstration, c’est bien sûr facultatif.
On va ajouter un peu de CSS :

/* empêche la sélection */
[draggable] {
    -moz-user-select: none;
    -khtml-user-select: none;
    -webkit-user-select: none;
    user-select: none;
}

#liste li {
    margin:4px;
    width:75px;
    border: 1px solid #000;
    border-radius:2px;
    cursor: move;
    text-align:center;
    padding:2px;
    box-shadow: 1px 1px 12px #555;
    background-color:white;
	list-style-type:none;
}
?

Voici le résultat :

Maintenant comment faire pour par exemple mettre A à la place de B et inversement ? HTML5 nous offre des événements pour gérer ça !
Le but de l’article n’est pas de faire une documentation, je vais vous donner le script complet et commenté pour que vous puissiez le comprendre.

Le code est organisé chronologiquement. Pour synthétiser, l’événement dragstart se déclenche au moment ou le clic gauche est pressé sur l’élément, ensuite lorsque vous bougez votre souris sur un élément draggable, c’est dragenter qui est déclenché, si vous le quittez, c’est dragleave qui prend le relais (à noter qu’entre le moment où vous déplacez l’élément et le moment où vous le lâchez, dragover est actionné).
Enfin, si vous lâchez l’élément sur un autre élément draggable, vous actionnerez l’événement drop. Dans tous les cas, au moment du relâchement, c’est dragend qui ferme la marche.

Il y a donc pas moins de 6 événements pour gérer le DnD. Sans plus attendre, je vous laisse découvrir le code :

// ajoute la propriété pour le drop et le transfert de données
$.event.props.push('dataTransfer');

$(document).ready(function() {
    var i, $this, $log = $('#log');

    $('#liste li').on({
        // on commence le drag
        dragstart: function(e) {
            $this = $(this);

            i = $this.index();
            $this.css('opacity', '0.5');

            // on garde le texte en mémoire (A, B, C ou D)
            e.dataTransfer.setData('text', $this.text());
        },
        // on passe sur un élément draggable
        dragenter: function(e) {
            // on augmente la taille pour montrer le draggable
            $(this).animate({
                width: '90px'
            }, 'fast');

            e.preventDefault();
        },
        // on quitte un élément draggable
        dragleave: function() {
            // on remet la taille par défaut
            $(this).animate({
                width: '75px'
            }, 'fast');
        },
        // déclenché tant qu on a pas lâché l élément
        dragover: function(e) {
            e.preventDefault();
        },
        // on lâche l élément
        drop: function(e) {
            // si l élément sur lequel on drop n'est pas l'élément de départ
            if (i !== $(this).index()) {
                // on récupère le texte initial
                var data = e.dataTransfer.getData('text');

                // on log
                $log.html(data + ' > ' + $(this).text()).fadeIn('slow').delay(1000).fadeOut();

                // on met le nouveau texte à la place de l ancien et inversement
                $this.text($(this).text());
                $(this).text(data);
            }

            // on remet la taille par défaut
            $(this).animate({
                width: '75px'
            }, 'fast');
        },
        // fin du drag (même sans drop)
        dragend: function() {
            $(this).css('opacity', '1');
        },
        // au clic sur un élément
        click: function() {
            alert($(this).text());
        }
    });
});

Un script comme celui-ci sans une page de démonstration ne serait vraiment pas intéressant ! :)

Vous aimerez aussi...