React-dnd: Prise en charge du déplacement de plusieurs éléments

Créé le 25 oct. 2014  ·  30Commentaires  ·  Source: react-dnd/react-dnd

Il existe un modèle commun qui est difficile à implémenter avec le glisser-déposer natif : faire glisser plusieurs éléments. Bien que les mécanismes de sélection puissent varier d'une application à l'autre (cmd+clic, cases à cocher, groupes prédéfinis), mais il serait bien de rendre au moins _possible_ la prise en charge de ce scénario.

screen shot 2014-10-26 at 1 07 07

Parce que plusieurs éléments glissés peuvent ne pas être frères dans DOM et que setDragImage(element, x, y) est assez fou et ne s'est pas amélioré, nous ne nous chargerons pas d'essayer de rendre plusieurs éléments dans l'aperçu du glisser à la fois.

Comment pouvons-nous aider à mettre en œuvre ce scénario, si nous ne pouvons pas afficher un aperçu de glisser « multiple » ?

D'une certaine manière, ce scénario est déjà possible : les consommateurs peuvent suivre manuellement les éléments sélectionnés, définir dragPreview sur une sorte d'espace réservé générique Image et réagir de manière appropriée à la suppression de (dans la mesure où les entreprises logique est concerné) plusieurs éléments.

Cependant, il n'existe actuellement aucun moyen pris en charge pour qu'un élément sache qu'il fait partie d'un groupe qui est déplacé. Du point de vue de react-dnd, si nous faisons glisser quelque chose, ce composant obtient getDragState(type).isDragging = true , mais pas les autres composants. Du point de vue de votre application, si vous prenez en charge la sélection multiple, vous voulez que tous les éléments "sélectionnés" logiquement sachent qu'ils sont déplacés, même si un seul d'entre eux est réellement "déplacé par le DOM".

Ce dont nous avons besoin, c'est d'un moyen pour les composants de dire à react-dnd que, « hé, bien que onDragStart été reçu par un autre composant, je veux prétendre que je suis aussi traîné et que mon getDragState(type) mirror a fait glisser le composant getDragState(type) , et j'ai aussi appelé mon endDrag(didDrop) pour que je puisse faire mes trucs”.

Comment les composants opteraient-ils pour cela?

design decisions

Commentaire le plus utile

Si quelqu'un est intéressé, j'ai implémenté une vue glisser/grille multiple : https://codesandbox.io/s/9j897k0mwy.
Vous pouvez utiliser les touches cmd/ctrl et shift pour sélectionner plusieurs éléments, puis les faire glisser dans la grille et les insérer n'importe où.

Il s'agit toujours d'une démo, mais je pourrais abstraire un peu plus le code et l'empaqueter plus tard dans un composant.

Tous les 30 commentaires

Pas une priorité. Nous pouvons revenir après avoir introduit les clés de source de glissement (https://github.com/gaearon/react-dnd/issues/38#issuecomment-73409935).

Cela m'intéressera plus tard, même si je pense que vous pourrez peut-être simplement envelopper une section de votre arborescence de composants avec un composant qui a un dragSource ...
Comme si vous maintenez la touche Maj enfoncée et cliquez, cela développe quelles sections du tableau sont copiées dans le dragItem ou quelque chose?

En quelque sorte.

D'abord, nous apprenons à passer un component nul (nécessaire pour #38) et un composant différent avec le même key (nécessaire pour #53).

Ensuite, nous ajoutons groupKey qui est facultatif. Comme key , il est spécifié dans la source de glissement et est une chaîne. Lorsque vous commencez à faire glisser quelque chose avec un groupKey , nous appellerons beginDrag non seulement sur l'appelant, mais sur chaque source de glissement montée avec le même groupKey , et rassemblerons leurs éléments dans un tableau. Nous passerons ces éléments au lieu de item pour supprimer les méthodes cibles. Une fois le glissement terminé, nous appellerons acceptDrop sur la cible de dépôt avec un tableau d'éléments, puis nous appellerons les endDrag chaque source de glissement avec leur élément.

Ce qui est amusant, c'est que nous pouvons dessiner DragLayer avec un composant de vignette "composite" personnalisé et un compteur comme j'ai fait la capture d'écran ci-dessus, car nous connaissons le nombre de items.length .

C'est une idée bien moins laide que ce que j'avais en tête

:+1: pour cette fonctionnalité :-)

Clôture, car je n'ai actuellement pas de cas d'utilisation pour cela, et c'est un effort de mise en œuvre important.

@gaearon

J'ai utilisé Java/Swing DnD à l'époque, et ils avaient probablement une armée de développeurs qui se sont attaqués à ce problème et ont proposé un cadre assez raffiné, extrêmement générique et flexible. Je recommanderais de rechercher d'anciens frameworks de bureau car ils ont probablement résolu tous les défis difficiles liés à la création d'un bon framework DnD comme celui-ci.

La façon de le faire dans Java/Swing (bien qu'il n'y ait pas de support intégré pour les images de glissement) était de _faire de l'arborescence elle-même la source du glissement_, et de lui permettre de décider si un glissement doit être lancé ou non en fonction de son l'état actuel et la position de départ du glissement_. Est-ce que monitor.getInitialSourceClientOffset() disponible lorsque canDrag et beginDrag sont appelés ? Les gens voudront certainement qu'il soit disponible. Ils voudront probablement aussi que les touches de modification (ctrl, alt, shift) soient disponibles et qu'elles puissent faire en sorte que les sources de glissement spécifient s'il faut déplacer ou copier, et déposer des cibles pour spécifier si elles prennent en charge le déplacement et/ou la copie, en fonction de l'un des ces facteurs, car cela est possible dans Java/Swing et je suppose que d'autres frameworks. Swing avait également le concept de _reconnaître les gestes de glissement_ qui pouvaient être échangés.

Je prédis que traiter tous les éléments de la liste comme des éléments déplaçables individuels sera simplement difficile par rapport au fait que le composant de liste soit la seule source de glissement qui détermine le type de charge utile / image d'aperçu à construire en fonction de ce qui y est sélectionné.

Considérez également qu'un développeur peut vouloir _changer l'ordre des éléments glissés en fonction de l'élément à partir duquel l'utilisateur a cliqué et glissé. _ Je pense que l'Explorateur Windows se comporte de cette façon.

Quelqu'un a-t-il implémenté le fait de faire glisser plusieurs éléments avec react-dnd dans leurs applications ? Quelle est votre solution actuelle pour cela?

vouliez-vous dire plusieurs cibles de dépôt pour une seule source de glissement ?

+1 @danii1 : Quelqu'un a-t-il implémenté le fait de faire glisser plusieurs éléments ?

Je l'ai implémenté, la solution est essentiellement ce qui est décrit dans le premier post :

  1. Gardez une trace de vos articles sélectionnés
  2. Implémentez CustomDragLayer (voir https://gaearon.github.io/react-dnd/docs-drag-layer.html) et affichez vous-même les éléments sélectionnés
  3. Gérer la suppression si l'élément déposé fait partie de la sélection

Je l'ai implémenté par :

  1. Gardez une trace des éléments sélectionnés dans un ensemble
  2. Transmettez ceci en tant que propriété au dnd Source
  3. Dans beginDrag, récupérez l'ensemble des accessoires et renvoyez-le en tant qu'élément de glissement
  4. Créer un aperçu de glisser personnalisé
  5. Sur EndDrag, déplacez tous les éléments de l'ensemble dans la cible dnd

J'ai un cas d'utilisation légèrement différent pour cela, je pense, je veux dessiner des nœuds qui sont déplaçables avec des bords qui ne sont pas déplaçables mais qui bougent lorsque les nœuds auxquels ils sont attachés se déplacent. Mon implémentation actuelle est un CustomDragLayer qui dessine les bords lorsqu'il détecte qu'un DraggableNode se déplace (également dessiné sur le CustomDragLayer mais je pense qu'il serait peut-être préférable de le modéliser comme un situation de traînée multiple en implémentant tous les bords en tant que DragSources avec isDragging() implémenté pour détecter si un nœud auquel ils sont attachés se déplace afin qu'ils puissent se dessiner au lieu d'avoir le CustomDragLayer injecter les coordonnées comme accessoires .

@danii1
Pouvez-vous s'il vous plaît partager celui que vous avez mis en œuvre pour une référence

Je vais écrire un article et ajouter un dépôt sur le glisser-déposer multiple et imbriqué avec react-dnd + redux.

@nayemmajhar , ce serait génial

@nayemmajhar une mise à jour sur un exemple avec ça ?

J'ai développé cette application en utilisant React DnD avec reduxJS il y a longtemps https://www.joomshaper.com/page-builder J'écris un tutoriel mais j'ai besoin de temps pour publier

@serle Pourriez-vous partager un exemple de code de la façon dont vous avez procédé ?

@ianmclean2011 consultez-le ici : https://github.com/react-dnd/react-dnd/issues/590

J'essaie d'implémenter le multi-drag dans un exemple similaire à l'exemple triable ici : https://react-dnd.github.io/react-dnd/examples-sortable-simple.html. Je veux pouvoir sélectionner n'importe quels objets, puis les déplacer comme une unité vers le haut et vers le bas de la liste. J'ai du mal à comprendre comment utiliser les exemples/informations partagés ci-dessus pour ce faire. Des pensées/idées/commentaires sur la façon dont cela pourrait fonctionner?

Si quelqu'un est intéressé, j'ai implémenté une vue glisser/grille multiple : https://codesandbox.io/s/9j897k0mwy.
Vous pouvez utiliser les touches cmd/ctrl et shift pour sélectionner plusieurs éléments, puis les faire glisser dans la grille et les insérer n'importe où.

Il s'agit toujours d'une démo, mais je pourrais abstraire un peu plus le code et l'empaqueter plus tard dans un composant.

@melvynhills Avez-vous étudié une solution qui ne nécessite pas de transmettre toutes les cartes sélectionnées à chaque composant de carte ? Je ne pense pas qu'il y ait de solution étant donné que le beginDrag() de la carte a besoin d'une référence à toutes les cartes sélectionnées.

@jmcrthrs Non, cela ne me semble pas possible avec l'API react-dnd. Je ne pense pas qu'il existe un moyen de savoir avant de faire glisser quel élément spécifique va être déplacé. C'est également le seul moyen de savoir si l'élément déplacé se trouve dans la sélection multiple que vous avez effectuée, ou s'il se trouve en dehors de cette sélection que nous devons ensuite remplacer.

@melvynhills @jmcrthrs d' autres frameworks dnd de bureau que j'ai utilisés reposent sur la création de listes et de tableaux comme sources de glissement/cibles de dépôt au lieu de faire de chaque ligne, cellule, élément, etc. sa propre source de glissement et/ou cible de dépôt. L'implémentation pour faire glisser plusieurs éléments, ainsi que pour obtenir l'emplacement de dépôt spécifique dans la liste ou le tableau, est beaucoup plus claire de cette façon. Lorsqu'une liste reçoit un événement de démarrage par glisser, elle peut simplement regarder ses éléments actuellement sélectionnés.

@jedwards1211 pensez -vous que c'est faisable avec cette bibliothèque ? Surtout le cas d'utilisation consistant à commencer à faire glisser un élément qui n'a pas été sélectionné avant le début du glissement. Je ne suis pas sûr que ce soit la façon dont react-dnd est censé fonctionner.

Quelqu'un a-t-il résolu le cas dans lequel il existe plusieurs cibles de dépôt ?
Disons que l'on fait glisser plusieurs éléments (en utilisant l'une des solutions ci-dessus) et qu'un élément se retrouve sur un type de cible de dépôt et l'autre sur un autre. drop sera déclenché uniquement pour la source de glissement qui a initié le glissement, mais pas pour l'autre. Toutes les idées sur la façon de déclencher la chute individuellement pour chaque élément déplacé.
Exemple:
Is development slow, Online Whiteboard for Visual Collaboration 2019-11-27 10-45-33

EDIT: Création d'un problème séparé pour celui-ci https://github.com/react-dnd/react-dnd/issues/1650

@melvynhills probablement si un gestionnaire mousedown déclenche la sélection d'éléments (ce que vous devriez faire, tous les logiciels avec DnD que j'ai utilisés fonctionnent de cette façon), cela fonctionnera très bien avec React DnD pour que le composant conteneur soit la traînée source, car les événements glisser viendront après mousedown .

Avez-vous étudié une solution qui ne nécessite pas de transmettre toutes les cartes sélectionnées à chaque composant de carte ?

C'est un exemple de la raison pour laquelle je recommanderais de faire du composant conteneur la source de glissement au lieu des éléments individuels. Je n'ai pas eu besoin d'implémenter la multisélection avec React DnD, mais peut-être que je pourrai parfois créer un bac à sable pour convaincre les gens que c'est l'approche la plus maintenable

Quelqu'un a-t-il implémenté le fait de faire glisser plusieurs éléments avec react-beautiful-dnd dans leurs applications ? Quelle est votre solution actuelle pour cela?

Cette page vous a été utile?
0 / 5 - 0 notes