API HTML5 Glisser-déposer

Cet article explique les bases du glisser-déposer.

Créer du contenu déplaçable

Dans la plupart des navigateurs, les sélections de texte, les images et les liens sont déplaçables par défaut. Par exemple, si vous faites glisser un lien sur une page Web, vous verrez une petite case avec un et l'URL que vous pouvez insérer dans la barre d'adresse ou sur le bureau ou accédez au lien. Pour rendre d'autres types de contenus déplaçables, vous utiliser les API de glisser-déposer HTML5.

Pour rendre un objet déplaçable, définissez draggable=true sur cet élément. À peu près tout élément pouvant être glissé, y compris les images, les fichiers, les liens, les fichiers, sur votre page.

L'exemple suivant crée une interface pour réorganiser les colonnes qui ont été avec la grille CSS. Le balisage de base des colonnes ressemble à ceci, avec l'attribut draggable pour chaque colonne définie sur true:

<div class="container">
  <div draggable="true" class="box">A</div>
  <div draggable="true" class="box">B</div>
  <div draggable="true" class="box">C</div>
</div>

Voici le code CSS des éléments "container" et "box". Le seul CSS associé la fonctionnalité de déplacement est cursor: move . Le reste du code contrôle la mise en page et le style du conteneur. et les éléments de zone.

.container {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
}

.box {
  border: 3px solid #666;
  background-color: #ddd;
  border-radius: .5em;
  padding: 10px;
  cursor: move;
}

À ce stade, vous pouvez faire glisser les éléments, mais rien d'autre ne se passe. Pour ajouter vous devez utiliser l'API JavaScript.

Écouter les événements de déplacement

Pour surveiller le processus de déplacement, vous pouvez écouter l'un des événements suivants:

Pour gérer le flux de déplacement, vous avez besoin d'un type d'élément source (où le déplacement la charge utile des données (ce que vous faites glisser) et une cible (une zone à attraper la baisse). L'élément source peut correspondre à presque n'importe quel type d'élément. La La cible est la zone de dépôt ou l'ensemble de zones de dépôt qui accepte les données de l'utilisateur que vous essayez de faire tomber. Tous les éléments ne peuvent pas être des cibles. Par exemple, votre cible ne peut pas en tant qu'image.

Commencer et terminer une séquence de déplacement

Après avoir défini les attributs draggable="true" pour votre contenu, associez une Gestionnaire d'événements dragstart pour lancer la séquence de déplacement pour chaque colonne.

Ce code définit l'opacité de la colonne sur 40% lorsque l'utilisateur commence à la faire glisser. puis remettez-le à 100% à la fin de l'événement de déplacement.

function handleDragStart(e) {
  this.style.opacity = '0.4';
}

function handleDragEnd(e) {
  this.style.opacity = '1';
}

let items = document.querySelectorAll('.container .box');
items.forEach(function (item) {
  item.addEventListener('dragstart', handleDragStart);
  item.addEventListener('dragend', handleDragEnd);
});

Vous pouvez voir le résultat dans la démonstration de Glitch suivante. Faites glisser un élément. l'opacité change. Étant donné que l'élément source contient l'événement dragstart, la définition this.style.opacity à 40% donne à l'utilisateur un retour visuel sur cet élément la sélection actuelle est déplacée. Lorsque vous déposez l'élément, l'élément source revient à 100% d'opacité, même si vous n'avez pas encore défini le comportement de dépôt.

Ajouter des repères visuels supplémentaires

Pour aider l'utilisateur à comprendre comment interagir avec votre interface, utilisez la Gestionnaires d'événements dragenter, dragover et dragleave Dans cet exemple, les colonnes sont des cibles de dépôt en plus d’être déplaçables. Aidez l’utilisateur à le comprendre en faisant en sorte que la bordure soit en pointillés lorsqu'ils tiennent un élément déplacé sur un . Par exemple, dans votre CSS, vous pouvez créer une classe over pour qui sont des cibles de dépôt:

.box.over {
  border: 3px dotted #666;
}

Ensuite, dans votre code JavaScript, configurez les gestionnaires d'événements, ajoutez la classe over lorsque la colonne est glissée et la supprime lorsque l'élément glissé quitte l'élément. Dans le gestionnaire dragend, nous veillons également à supprimer les classes à la fin de faites glisser.

document.addEventListener('DOMContentLoaded', (event) => {

  function handleDragStart(e) {
    this.style.opacity = '0.4';
  }

  function handleDragEnd(e) {
    this.style.opacity = '1';

    items.forEach(function (item) {
      item.classList.remove('over');
    });
  }

  function handleDragOver(e) {
    e.preventDefault();
    return false;
  }

  function handleDragEnter(e) {
    this.classList.add('over');
  }

  function handleDragLeave(e) {
    this.classList.remove('over');
  }

  let items = document.querySelectorAll('.container .box');
  items.forEach(function(item) {
    item.addEventListener('dragstart', handleDragStart);
    item.addEventListener('dragover', handleDragOver);
    item.addEventListener('dragenter', handleDragEnter);
    item.addEventListener('dragleave', handleDragLeave);
    item.addEventListener('dragend', handleDragEnd);
    item.addEventListener('drop', handleDrop);
  });
});

Voici quelques points à aborder dans ce code:

  • L'action par défaut pour l'événement dragover consiste à définir la propriété dataTransfer.dropEffect sur "none" La propriété dropEffect est abordée plus loin sur cette page. Pour l'instant, sachez simplement qu'il empêche le déclenchement de l'événement drop. Pour remplacer , appelez e.preventDefault(). Une autre bonne pratique consiste à renvoyer false dans ce même gestionnaire.

  • Le gestionnaire d'événements dragenter permet d'activer/de désactiver la classe over au lieu de dragover Si vous utilisez dragover, l'événement se déclenche plusieurs fois lorsque l'utilisateur maintient l'élément déplacé sur une colonne, ce qui entraîne l'activation/désactivation de la classe CSS à plusieurs reprises. Cela fait que le navigateur effectue beaucoup de tâches inutiles d’affichage, ce qui peut affecter l'expérience utilisateur. Nous vous recommandons vivement de réduire redessin, et si vous devez utiliser dragover, envisagez en limitant ou en bloquant l'écouteur d'événements.

Terminez le lancement

Pour traiter la suppression, ajoutez un écouteur d'événements pour l'événement drop. Dans le drop vous devez empêcher le comportement par défaut du navigateur en cas de suppression, est généralement une redirection agaçante. Pour ce faire, appelez e.stopPropagation().

function handleDrop(e) {
  e.stopPropagation(); // stops the browser from redirecting.
  return false;
}

Veillez à enregistrer le nouveau gestionnaire en même temps que les autres gestionnaires:

  let items = document.querySelectorAll('.container .box');
  items.forEach(function(item) {
    item.addEventListener('dragstart', handleDragStart);
    item.addEventListener('dragover', handleDragOver);
    item.addEventListener('dragenter', handleDragEnter);
    item.addEventListener('dragleave', handleDragLeave);
    item.addEventListener('dragend', handleDragEnd);
    item.addEventListener('drop', handleDrop);
  });

Si vous exécutez le code à ce stade, l'élément ne passe pas au nouvel emplacement. À utilisez la méthode DataTransfer .

La propriété dataTransfer contient les données envoyées lors d'un déplacement. dataTransfer est défini dans l'événement dragstart, et lu ou géré dans l'événement de dépôt. Appel en cours e.dataTransfer.setData(mimeType, dataPayload) vous permet de définir la méthode MIME de l'objet et la charge utile des données.

Dans cet exemple, nous allons permettre aux utilisateurs de réorganiser l'ordre des colonnes. Pour ce faire, vous devez d'abord stocker le code HTML de l'élément source lorsque le déplacement début:

function handleDragStart(e) {
  this.style.opacity = '0.4';

  dragSrcEl = this;

  e.dataTransfer.effectAllowed = 'move';
  e.dataTransfer.setData('text/html', this.innerHTML);
}

Dans l'événement drop, vous traitez la suppression de colonne en définissant le paramètre HTML au code HTML de la colonne cible dans laquelle vous avez déposé les données. Ce inclut la vérification que l'utilisateur ne revient pas dans la même colonne qu'il que nous avons glissé.

function handleDrop(e) {
  e.stopPropagation();

  if (dragSrcEl !== this) {
    dragSrcEl.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text/html');
  }

  return false;
}

Vous pouvez observer le résultat dans la démonstration suivante. Pour que cela fonctionne, vous devez disposer d'un navigateur pour ordinateur. L'API de glisser-déposer n'est pas prise en charge sur mobile. Faire glisser et relâchez la colonne A au-dessus de la colonne B et notez la façon dont elles changent:

Autres propriétés de déplacement

L'objet dataTransfer expose les propriétés pour fournir un retour visuel à la l'utilisateur pendant le processus de glissement et contrôler la manière dont chaque cible de dépôt répond à une un type de données particulier.

  • dataTransfer.effectAllowed limite le "type de déplacement" que l'utilisateur peut effectuer sur l'élément. Il est utilisé dans le modèle de traitement par glisser-déposer pour initialiser dropEffect pendant les événements dragenter et dragover. La propriété peut être définie sur valeurs suivantes: none, copy, copyLink, copyMove, link, linkMove, move, all et uninitialized.
  • dataTransfer.dropEffect contrôle les commentaires reçus par l'utilisateur pendant les actions dragenter et dragover événements. Lorsque l'utilisateur maintient le pointeur sur un élément cible, Le curseur indique le type d'opération qui va avoir lieu, comme une copie ou un mouvement. L'effet peut prendre l'une des valeurs suivantes: none, copy, link et move.
  • e.dataTransfer.setDragImage(imgElement, x, y) signifie qu'au lieu d'utiliser l'image fantôme par défaut du navigateur, commentaires, vous vous pouvez définir une icône de déplacement.

Importer des fichiers

Cet exemple simple utilise une colonne à la fois comme source de déplacement et cible de déplacement. Ce peut se produire dans une interface utilisateur qui demande à l'utilisateur de réorganiser les éléments. Dans certaines situations, la cible et la source peuvent être des types d'éléments différents, comme dans une interface où l’utilisateur doit sélectionner une image comme image principale d’un produit en en faisant glisser l'image sélectionnée vers une cible.

Le glisser-déposer est fréquemment utilisé pour permettre aux utilisateurs de faire glisser des éléments de leur bureau vers une application. La principale différence réside dans votre gestionnaire drop. Au lieu d'utiliser dataTransfer.getData() pour accéder aux fichiers, leurs données sont contenues dans le Propriété dataTransfer.files:

function handleDrop(e) {
  e.stopPropagation(); // Stops some browsers from redirecting.
  e.preventDefault();

  var files = e.dataTransfer.files;
  for (var i = 0, f; (f = files[i]); i++) {
    // Read the File objects in this FileList.
  }
}

Pour en savoir plus à ce sujet, consultez Glisser-déposer personnalisé :

Autres ressources