Public Markdown Document
FAQ Reordenação Drag & Drop (Perguntas Frequentes)
R : Adicione a prop sortable="true" ao DynamicList:
FAQ - Reordenação Drag & Drop (Perguntas Frequentes)
❓ Perguntas sobre Funcionalidade
P: Como ativo a reordenação no meu componente?
R: Adicione a prop sortable="true" ao DynamicList:
<DynamicList
:schema="schema"
:data="data"
:sortable="true"
@reorder="handleReorder"
/>
P: Qual é a diferença entre DynamicList e PropertyListEditor?
R:
- DynamicList.vue: Componente genérico para exibir coleções de dados com reordenação opcional
- PropertyListEditor.vue: Componente especializado para editar propriedades de objetos (metadados) com suporte completo a inline-editing
P: O que é o "drag-handle"?
R: É o ícone ⋮⋮ (seis pontos) que aparece no início de cada linha quando sortable="true". Você deve clicar/arrastar nele para mover a linha de posição.
P: Preciso atualizar a API quando reordenar?
R: Não imediatamente. O componente emite o evento reorder com a nova ordem. Você deve:
- Capturar o evento
- Marcar como "dirty" (isDirty = true)
- Aguardar o usuário clicar "Salvar"
- Então enviar para a API
P: Como funciona a sincronização com o estado "dirty"?
R:
@reorder="(newList) => {
isDirty = true; // Marca como modificado
dataList = newList; // Atualiza dados locais
toast.add({ severity: 'info', summary: 'Alteração pendente' });
}"
P: Posso reordenar dentro de um grupo específico?
R: Sim. Use a propriedade group no componente:
const dragOptions = {
group: "meu-grupo", // Restringe a qual grupo pode arrastar
// ...
}
P: O que acontece se o usuário sair sem salvar?
R: Dois comportamentos:
- PropertyListEditor: Detecta isDirty e avisa ("Existem alterações não salvas")
- DynamicList: Sem gestão de dirty, você controla no componente pai
❓ Perguntas sobre UI/UX
P: Como faço o handle aparecer apenas ao passar o mouse?
R: Atualmente ele aparece sempre. Se quiser mudar, adicione CSS:
.drag-handle {
opacity: 0.3; /* Invisível */
}
.record-card:hover .drag-handle {
opacity: 1; /* Visível ao passar mouse */
}
P: Posso customizar o ícone do handle?
R: Sim! Edite em DynamicList.vue ou PropertyListEditor.vue:
<!-- Antes -->
<i class="pi pi-bars text-gray-400 text-sm"></i>
<!-- Depois (exemplo com ícone de drag) -->
<i class="pi pi-arrow-down-up text-gray-400 text-sm"></i>
P: Qual é a cor durante o arraste?
R: Configurada em CSS no .drag class:
.drag {
opacity: 1;
transform: rotate(2deg) scale(1.02);
box-shadow: 0 5px 25px rgba(99, 102, 241, 0.3); /* Azul índigo */
}
P: Posso mudar a duração da animação?
R: Sim, no dragOptions:
const dragOptions = {
animation: 200, // ms (mude aqui)
// ...
}
P: Como funciona no mobile?
R: Funciona normalmente, mas considere:
- Handle talvez seja pequeno (aumentar em mobile)
- Arraste de toque é suportado
- Recomenda-se aumentar padding em telas pequenas
❓ Perguntas sobre Dados
P: Os dados são salvos automaticamente ao reordenar?
R: Não. Você deve:
- Capturar evento
reorder - Atualizar estado local
- Manualmente chamar API ao clicar "Salvar"
Exemplo:
function handleReorder(newOrder) {
localData.value = newOrder; // Local
isDirty.value = true; // Marcar como pendente
// Não salva ainda!
}
P: Como garanto que a ordem é única?
R: A ordem é determinada pelo índice no array. Vue mantém a reatividade automaticamente.
P: E se duas propriedades tiverem o mesmo nome?
R: Isso causaria conflito. Implemente validação:
function validatePropertyName(newName) {
const exists = editingObject.properties.some(p => p.name === newName);
if (exists) {
toast.add({ severity: 'error', summary: 'Nome já existe' });
return false;
}
return true;
}
P: Como desfaço uma reordenação?
R: Três opções:
- Sem salvar: Recarregue a página (dados não salvos são perdidos)
- Com salvar: Reordene novamente manualmente
- Undo avançado: Implemente stack de mudanças (ver roadmap)
P: Posso reordenar entre múltiplas listas?
R: Apenas se as listas tiverem o mesmo group:
// Lista A
const dragOptionsA = { group: "shared" };
// Lista B
const dragOptionsB = { group: "shared" };
// Agora itens podem ir de A para B e vice-versa
❓ Perguntas sobre Performance
P: Qual é o limite de propriedades que posso reordenar?
R: Teoricamente ilimitado, mas:
- < 50: Muito rápido
- 50-200: Rápido
- 200+: Considere virtualização (ainda não implementada)
P: Há lag ao arrastar muitos itens?
R: Se houver, verifique:
- Número de computed properties
- Watchers profundos
- Tamanho dos dados renderizados
- Performance do navegador (DevTools > Performance)
P: Como otimizo a renderização?
R:
// ✅ BOM: Computed para dados filtrados
const visibleProperties = computed(() => {
return properties.value.filter(p => p.show_in_list);
});
// ❌ EVITE: Lógica no template
<div v-for="p in properties.filter(p => p.show_in_list)">
P: Devo usar v-key="item.id" ou v-key="index"?
R: Sempre item.id se disponível. O índice muda ao reordenar, causando re-renders desnecessários.
❓ Perguntas sobre Integração
P: Como integro com dados do backend?
R:
// 1. Fetch dos dados
const properties = ref([]);
onMounted(async () => {
properties.value = await $fetch('/api/object/lead/properties');
});
// 2. Componente com sortable
<PropertyListEditor
:properties="properties"
@reorder="onReorder"
/>
// 3. Handler
function onReorder(newOrder) {
isDirty = true;
// Salvar mais tarde com API call
}
P: Como funciona com Pinia store?
R:
// store/object.ts
const properties = ref([]);
function setProperties(newProperties) {
properties.value = newProperties;
}
function reorderProperties(newOrder) {
properties.value = newOrder;
isDirty = true; // Marcar store como dirty
// Salvar quando necessário
}
P: Como sincronizo com Sistema de Manifesto?
R: O Schema Manager já faz isso. Seu objeto é:
editingObject.value.properties = reorderedProperties; // Atualiza referência
isDirty.value = true; // Marca para salvar
❓ Perguntas sobre Debugging
P: Como vejo quais eventos estão sendo disparados?
R: Adicione logs no handler:
function onReorder(newOrder) {
console.log('[REORDER EVENT]', newOrder);
console.log('[ORDER NAMES]', newOrder.map(p => p.name));
}
P: Como verifico o estado drag durante animação?
R: Use DevTools:
- Abra Elements/Inspector
- Selecione um item durante arraste
- Veja classe
.dragsendo aplicada
P: Como verifico se isDirty está sendo marcado?
R:
watch(() => isDirty.value, (newVal) => {
console.log('[DIRTY CHANGED]', newVal);
});
P: Por que o evento reorder é emitido múltiplas vezes?
R: Verifique se você tem múltiplos watchers:
// ❌ PROBLEMA: Watcher duplicado
watch(properties, () => {
emit('reorder', properties.value); // Emite sempre que muda
});
// ✅ SOLUÇÃO: Emita apenas no @end do draggable
@end="onDragEnd"
❓ Perguntas sobre Erros Comuns
P: "Cannot read property 'name' of undefined"
R: Propriedade está null. Verifique:
// ✅ BOM: Validação
const propName = property?.name || 'Unknown';
// ❌ EVITE: Sem checar
const propName = property.name; // Erro se property = null
P: Array não atualiza após reordenar
R: Você está mutando diretamente? Use Vue.set:
// ❌ ERRADO
properties[0] = newValue; // Vue não detecta
// ✅ CORRETO
properties.value[0] = newValue; // Reativo
// ou
properties.value = [...properties.value]; // Novo array
P: Drag & Drop não funciona
R: Verifique:
vuedraggableestá importado?- Prop
sortable="true"foi adicionado? - Handle
.drag-handleexiste no template? - Browser suporta drag & drop?
P: Estilos não aplicam durante arraste
R: Você está importando o CSS de .drag?
<style scoped>
.drag {
opacity: 1;
box-shadow: 0 5px 25px rgba(99, 102, 241, 0.3);
}
</style>
❓ Perguntas sobre Acessibilidade
P: Como faço reordenação acessível via teclado?
R: Isso ainda não foi implementado. Você pode:
- Adicionar botões "Mover Para Cima"/"Mover Para Baixo"
- Usar Shift + Setas para reordenar (custom)
- Implementar ARIA labels
Exemplo de botões:
<Button
icon="pi pi-arrow-up"
@click="moveUp(idx)"
aria-label="Mover para cima"
/>
<Button
icon="pi pi-arrow-down"
@click="moveDown(idx)"
aria-label="Mover para baixo"
/>
P: Qual é o aria-label do handle?
R: Não tem atualmente. Adicione se necessário:
<div class="drag-handle" aria-label="Arrastar para reordenar">
❓ Perguntas sobre Roadmap
P: Vocês vão implementar Undo/Redo?
R: Não está planned ainda, mas é possível usando:
const history = ref([]);
const historyIndex = ref(-1);
function saveToHistory() {
history.value = history.value.slice(0, historyIndex.value + 1);
history.value.push(JSON.parse(JSON.stringify(properties.value)));
historyIndex.value++;
}
function undo() {
if (historyIndex.value > 0) {
historyIndex.value--;
properties.value = JSON.parse(JSON.stringify(history.value[historyIndex.value]));
}
}
P: Quando virá array virtual para 1000+ itens?
R: Não está planneed. Use paginação ou virtualScroller de PrimeVue.
P: Vocês vão adicionar persistência automática?
R: Considere debounce + auto-save:
const saveToDebounce = useDebounceFn(saveChanges, 2000);
function onReorder(newOrder) {
isDirty.value = true;
saveToDebounce(); // Salva automaticamente após 2s
}
❓ Perguntas sobre Suporte
P: Funciona em Safari?
R: Sim, com vuedraggable 4.0+. Tested em Safari 15+.
P: Funciona em IE11?
R: Não. Suporte apenas para navegadores modernos (Chrome, Firefox, Safari, Edge).
P: Posso usar com jQuery?
R: Não, este é um projeto Vue 3. jQuery não é suportado.
P: Qual é o licença deste código?
R: Mesmo projeto (verificar LICENSE.md).
📞 Contato & Suporte
Se você não encontrou resposta aqui:
- Verifique IMPLEMENTATION_DRAG_DROP.md
- Verifique TESTING_GUIDE.md
- Procure nos comentários do código
- Abra uma issue no GitHub
Última Atualização: 17/02/2026