React-dnd: Suporte para arrastar vários elementos

Criado em 25 out. 2014  ·  30Comentários  ·  Fonte: react-dnd/react-dnd

Existe um padrão comum que é difícil de implementar com arrastar e soltar nativo: arrastar vários elementos. Embora a mecânica de seleção possa variar de aplicativo para aplicativo (cmd + clicar, caixas de seleção, grupos predefinidos), seria bom pelo menos tornar _possível_ o suporte a este cenário.

screen shot 2014-10-26 at 1 07 07

Como vários itens arrastados podem não ser irmãos no DOM e setDragImage(element, x, y) é muito insano e não melhorou, não vamos nos preocupar em tentar renderizar vários elementos na visualização do arrasto de uma vez.

Como podemos ajudar a implementar este cenário, se não podemos mostrar uma visualização de arrasto "múltiplo"?

De certa forma, este cenário já é possível: os consumidores podem controlar manualmente os elementos selecionados, definir dragPreview para algum tipo de marcador genérico Image e reagir apropriadamente à queda de (no que diz respeito aos negócios lógica) vários elementos.

No entanto, atualmente não há uma maneira compatível de um elemento saber que faz parte de um grupo que está sendo arrastado. Do ponto de vista de react-dnd, se arrastarmos algo, este componente obtém getDragState(type).isDragging = true , mas outros componentes não. Do ponto de vista do seu aplicativo, se você oferece suporte à seleção múltipla, deseja que todos os itens "selecionados" logicamente estejam cientes de que estão sendo arrastados, mesmo se apenas um deles estiver sendo realmente "arrastado pelo DOM".

O que precisamos é uma maneira de os componentes informarem a reação-dnd que, "ei, embora onDragStart sido recebido por outro componente, quero fingir que também estou sendo arrastado e tenho meu getDragState(type) componente arrastado do espelho getDragState(type) , e meu endDrag(didDrop) chamado também para que eu pudesse fazer minhas coisas ”.

Como os componentes optariam por isso?

design decisions

Comentários muito úteis

Se alguém estiver interessado, implementei uma exibição de arrastar / grade múltipla: https://codesandbox.io/s/9j897k0mwy.
Você pode usar as teclas cmd / ctrl e shift para selecionar vários itens e, em seguida, arrastá-los pela grade e inseri-los em qualquer lugar.

Isso ainda é uma demonstração, mas posso abstrair o código um pouco mais e empacotá-lo em um componente posteriormente.

Todos 30 comentários

Não é uma prioridade. Podemos revisitar depois de introduzir as chaves de origem de arrastar (https://github.com/gaearon/react-dnd/issues/38#issuecomment-73409935).

Estarei interessado nisso no futuro, embora eu ache que você possa apenas envolver uma seção de sua árvore de componentes com um componente que tem um dragSource ...
Por exemplo, se você segurar a tecla shift e clicar, ele expande quais seções do array são copiadas para o dragItem ou algo assim?

Tipo.

Primeiro, aprendemos a passar nulo component (necessário para # 38) e um componente diferente com o mesmo key (necessário para # 53).

Em seguida, adicionamos groupKey que é opcional. Como key , ele é especificado na fonte de arrastar e é uma string. Quando você começar a arrastar algo com groupKey , chamaremos beginDrag não apenas do autor da chamada, mas de cada fonte de arrastar montada com o mesmo groupKey , e reuniremos seus itens em uma matriz. Vamos passar esses itens em vez de item para eliminar os métodos de destino. Quando o arrastamento terminar, chamaremos acceptDrop no destino de soltar com um array de itens e, em seguida, chamaremos endDrag cada fonte de arrastar com seu item.

O que é divertido é que podemos desenhar DragLayer com um componente de miniatura “composto” personalizado e um contador como o da captura de tela acima, porque sabemos a contagem de items.length .

Essa é uma ideia bem menos feia do que a que eu tinha em mente

: +1: para este recurso :-)

Fechando, já que atualmente não tenho um caso de uso para isso e é um esforço de implementação significativo.

@gaearon

Eu usei Java / Swing DnD no passado, e eles provavelmente tinham um exército de desenvolvedores que lutaram com esse problema e criaram uma estrutura bastante refinada, extremamente genérica e flexível. Eu recomendaria pesquisar estruturas de desktop antigas, pois elas provavelmente resolveram todos os desafios difíceis de fazer uma boa estrutura de DnD como essa.

A maneira de fazer isso em Java / Swing (embora não tivesse suporte embutido para arrastar imagens) era _tornar a própria visualização em árvore a fonte de arrastar_ e torná-la _possível decidir se um arrastar deveria ou não ser iniciado com base em seu estado atual e a posição inicial do arrasto_. monitor.getInitialSourceClientOffset() disponível quando canDrag e beginDrag são chamados? As pessoas definitivamente vão querer que ele esteja disponível. Eles provavelmente também vão querer que as teclas modificadoras (ctrl, alt, shift) estejam disponíveis e sejam capazes de fazer as fontes de arrastar especificar se devem mover ou copiar, e soltar os alvos para especificar se eles suportam mover e / ou copiar, com base em qualquer um dos esses fatores, porque isso é possível em Java / Swing e estou adivinhando outras estruturas. O Swing também tinha o conceito de _reconhecedores de gestos de arrastar_ que podiam ser trocados.

Eu prevejo que tratar todos os itens na lista como arrastáveis ​​individuais será apenas difícil em comparação a ter o componente da lista como a única fonte de arrastar que descobre que tipo de imagem de visualização / carga útil de soltar construir com base no que está selecionado nela.

Considere também que um desenvolvedor pode querer _alterar a ordem dos itens que estão sendo arrastados com base no item de onde o usuário clicou e arrastou._ Acredito que o Windows Explorer se comporta dessa maneira.

Alguém implementou arrastar vários itens com react-dnd em seus aplicativos? Qual é a sua solução atual para isso?

você quis dizer múltiplos destinos de soltar para uma única fonte de arrasto?

+1 @ danii1 : Alguém implementou arrastar vários itens?

Eu implementei, a solução é basicamente o que está descrito no primeiro post:

  1. Acompanhe os itens selecionados
  2. Implemente CustomDragLayer (consulte https://gaearon.github.io/react-dnd/docs-drag-layer.html) e renderize você mesmo os itens selecionados
  3. Lidar com a queda se o item solto fizer parte da seleção

Eu implementei por:

  1. Acompanhe os itens selecionados em um Conjunto
  2. Passe isso como uma propriedade para a fonte dnd
  3. Em beginDrag recupere o conjunto de adereços e devolva-o como o item de arrastar
  4. Crie uma visualização de arrastar personalizada
  5. No EndDrag, mova todos os itens do Conjunto para o alvo dnd

Eu tenho um caso de uso ligeiramente diferente para isso, eu acho, eu quero desenhar nós que são arrastáveis ​​com arestas que não podem ser arrastadas, mas se movem quando os nós são anexados para se mover. Minha implementação atual é um CustomDragLayer que desenha as bordas quando detecta que DraggableNode está se movendo (também desenhado no CustomDragLayer mas acho que pode ser melhor modelá-lo como um situação de arrasto múltiplo implementando todas as arestas como DragSources com isDragging() implementado para detectar se um nó ao qual eles estão anexados está se movendo para que eles possam desenhar a si mesmos em vez de ter CustomDragLayer injetar as coordenadas como suportes .

@ danii1
Você pode compartilhar o que você implementou para uma referência

Vou escrever um post e adicionar repo sobre arrastar e soltar múltiplo e aninhado com react-dnd + redux.

@nayemmajhar , seria ótimo

@nayemmajhar alguma atualização em um exemplo com isso?

Eu desenvolvi este aplicativo usando o react DnD com reduxJS há muito tempo https://www.joomshaper.com/page-builder Estou escrevendo um tutorial, mas preciso de tempo para publicar

@serle Você poderia compartilhar um exemplo de código de como você fez isso?

Estou tentando implementar o multi-drag em um exemplo semelhante ao exemplo classificável aqui: https://react-dnd.github.io/react-dnd/examples-sortable-simple.html. Quero poder selecionar quaisquer objetos e movê-los como uma unidade para cima e para baixo na lista. Estou tendo problemas para entender como usar os exemplos / informações compartilhados acima para fazer isso. Algum pensamento / ideia / feedback sobre como isso pode funcionar?

Se alguém estiver interessado, implementei uma exibição de arrastar / grade múltipla: https://codesandbox.io/s/9j897k0mwy.
Você pode usar as teclas cmd / ctrl e shift para selecionar vários itens e, em seguida, arrastá-los pela grade e inseri-los em qualquer lugar.

Isso ainda é uma demonstração, mas posso abstrair o código um pouco mais e empacotá-lo em um componente posteriormente.

@melvynhills Você investigou uma solução que não exige a passagem de todos os cartões selecionados para cada componente do cartão? Não acho que haja uma solução considerando que o beginDrag () do Card precisa de uma referência para todos os Cards selecionados.

@jmcrthrs Não, não me parece possível com a API react-dnd. Não acho que haja uma maneira de saber antes de arrastar qual item específico será arrastado. Essa também é a única maneira de saber se o item arrastado está dentro da seleção múltipla que você fez ou se está fora da seleção que precisamos substituir.

@melvynhills @jmcrthrs outros frameworks dnd de desktop que usei contam com a criação de listas e tabelas como fontes de arrastar / destinos de soltar, em vez de tornar cada linha individual, célula, item etc. sua própria fonte de arrastar e / ou destino de soltar. A implementação para arrastar vários itens, bem como obter o local específico para soltar na lista ou tabela, fica muito mais limpa dessa maneira. Quando uma lista recebe um evento de início de arrasto, ela pode simplesmente examinar seus itens selecionados no momento.

@ jedwards1211 você acha que é possível com esta biblioteca? Especialmente o caso de uso de começar a arrastar um item que não foi selecionado antes do início do arrasto. Não tenho certeza se é a maneira como o react-dnd deve funcionar.

Alguém resolveu o caso em que há vários alvos de soltar?
Digamos que um esteja arrastando vários itens (usando uma das soluções acima) e um item termine em um tipo de destino de soltar e o outro em outro. drop será acionado apenas para a fonte de arrasto que iniciou o arrasto, mas não para a outra. Todas as idéias de como acionar a queda individualmente para cada item que está sendo movido.
Exemplo:
Is development slow, Online Whiteboard for Visual Collaboration 2019-11-27 10-45-33

EDIT: Problema separado criado para este https://github.com/react-dnd/react-dnd/issues/1650

@melvynhills provavelmente se um manipulador mousedown disparar a seleção de item (o que você deveria estar fazendo, todos os softwares com DnD que usei funcionam dessa forma), funcionará muito bem com React DnD para o componente do contêiner ser o arrasto fonte, porque os eventos de arrastar virão depois de mousedown .

Você investigou uma solução que não exige a passagem de todos os cartões selecionados para cada componente do cartão?

Este é um exemplo de porque eu recomendaria tornar o componente do contêiner a fonte de arrastar em vez dos itens individuais. Eu não precisei implementar multiselect com React DnD, mas talvez algum dia eu possa fazer uma sandbox para convencer as pessoas de que é a abordagem mais sustentável

Alguém implementou arrastar vários itens com react-beautiful-dnd em seus aplicativos? Qual é a sua solução atual para isso?

Esta página foi útil?
0 / 5 - 0 avaliações