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.
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?
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:
Eu implementei por:
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?
@ ianmclean2011 confira aqui: https://github.com/react-dnd/react-dnd/issues/590
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:
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?
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.