Naive UI предоставляет встроенные возможности для реализации
drag-and-drop интерфейсов через компоненты и директивы, что упрощает
создание интерактивных элементов с перемещением внутри страницы.
Основными инструментами являются компоненты NTransfer,
NTable, NTree и использование событий для
отслеживания drag и drop. Для работы с
drag-and-drop важно понимать концепцию событий и
слотов, которые позволяют точно контролировать поведение
перетаскиваемого элемента и зоны, в которую он перемещается.
Чтобы элемент был перетаскиваемым, необходимо:
draggable="true" к элементу.@dragstart, чтобы определить
данные, передаваемые при начале перетаскивания.@dragend для
логики после завершения операции.Пример базового элемента:
<template>
<div
class="draggable-item"
draggable="true"
@dragstart="handleDragStart"
@dragend="handleDragEnd"
>
Перетащи меня
</div>
</template>
<script setup>
import { ref } from 'vue';
const handleDragStart = (event) => {
event.dataTransfer.setData('text/plain', 'item1');
};
const handleDragEnd = (event) => {
console.log('Перетаскивание завершено');
};
</script>
<style>
.draggable-item {
width: 150px;
height: 50px;
background-color: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
cursor: grab;
border: 1px solid #ccc;
}
.draggable-item:active {
cursor: grabbing;
}
</style>
drop zone)Для зоны, которая принимает элементы, необходимо:
@dragover с вызовом
event.preventDefault() — без этого элемент не сможет быть
“брошен”.@drop, чтобы получить данные и выполнить
перемещение.Пример:
<template>
<div
class="drop-zone"
@dragover.prevent
@drop="handleDrop"
>
Бросьте элемент сюда
</div>
</template>
<script setup>
const handleDrop = (event) => {
const data = event.dataTransfer.getData('text/plain');
console.log('Элемент брошен:', data);
};
</script>
<style>
.drop-zone {
width: 300px;
height: 200px;
border: 2px dashed #007acc;
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
}
</style>
NTableКомпонент NTable поддерживает drag-and-drop через
пользовательские слоты и события:
<NTable :columns="columns" :data="tableData">
<template #body-cell="{ row, column }">
<div
draggable="true"
@dragstart="startDrag(row)"
@drop="dropRow(row)"
@dragover.prevent
>
{{ row[column.key] }}
</div>
</template>
</NTable>
Логика для перемещения строк:
const draggedRow = ref(null);
function startDrag(row) {
draggedRow.value = row;
}
function dropRow(targetRow) {
if (!draggedRow.value || draggedRow.value === targetRow) return;
const indexFrom = tableData.indexOf(draggedRow.value);
const indexTo = tableData.indexOf(targetRow);
tableData.splice(indexFrom, 1);
tableData.splice(indexTo, 0, draggedRow.value);
draggedRow.value = null;
}
NTree с перетаскиваниемNTree поддерживает drag-and-drop через свойства
draggable и события onDrop:
<NTree
:data="treeData"
:draggable="true"
@dragstart="onDragStart"
@drop="onDrop"
/>
Пример обработки:
let draggedNode = null;
function onDragStart(node) {
draggedNode = node;
}
function onDrop({ node: targetNode, dropPosition }) {
if (!draggedNode || draggedNode === targetNode) return;
// Удаляем из исходного родителя
const parent = findParentNode(treeData, draggedNode);
parent?.children?.splice(parent.children.indexOf(draggedNode), 1);
// Вставляем в новый родитель
if (!targetNode.children) targetNode.children = [];
targetNode.children.splice(dropPosition === 'inside' ? 0 : targetNode.children.length, 0, draggedNode);
draggedNode = null;
}
drop zone или изменение прозрачности перетаскиваемого
элемента.NTree) следует точно учитывать
позицию вставки (before, after,
inside).touchstart, touchmove и touchend,
так как стандартные HTML5 drag/drop не поддерживаются.draggedItems и при drop вставлять все
сразу.NTable сортировка и фильтры не должны сбрасывать состояние
drag-and-drop, поэтому лучше использовать уникальные ключи
элементов.VueUse + transition-group).Naive UI позволяет гибко сочетать стандартные HTML drag-and-drop возможности с реактивной логикой Vue, обеспечивая простую реализацию интерактивных интерфейсов для таблиц, деревьев и списков с минимальным количеством кода.