Создание простейшего компонента перетаскивания на Vue.js
Предположим, что у нас есть некоторый массив с элементами. Каждый из них представляет собой объект со свойством title. При перемещении элементов задействовано несколько событий: mousedown, mousemove и mouseover. Сначала необходимо разделить эти три события на отдельные этапы: кликаем по элементу (чтобы перетащить его), перетаскиваем и отпускаем.

Шаг 1
На первом этапе нужно определить, на каком элементе происходит перетаскивание, и сделать его слегка «прилипающим» к курсору. На данный момент у нас должно быть три метода:
methods: {
myDrag(key, event) {
this.draggableIndex = key;
this.moveAt(event);
},
moveAt(event){
if(this.draggableIndex !== -1){
this.dragLeft = event.pageX - 12;
this.dragTop = event.pageY - 12;
}
},
myDragStop() {
// сбрасываем все значения к начальным
this.draggableIndex = -1;
this.dragLeft = 0;
this.dragTop = 0;
},
isDragging(key) {
return this.draggableIndex === key;
},
positionByKey(key) {
return this.isDragging(key) ? 'absolute' : 'relative'
},
leftByKey(key) {
return this.isDragging(key) ? this.dragLeft + 'px' : 0
},
topByKey(key) {
return this.isDragging(key) ? this.dragTop + 'px' : 0
},
}
Число 12 – это координаты значка перетаскивания. Как же обработать draggableIndex, dragTop и dragLeft в шаблоне?
<template>
<ul id="my-list" v-on:mousemove="moveAt">
<li v-for="(item, key) in items" ref="li"
v-bind:style="{
position: positionByKey(key),
left: leftByKey(key),
top: topByKey(key),
}">
<i class="fa fa-arrows-alt"
v-on:mousedown="myDrag(key, $event)"
v-on:mouseup="myDragStop"></i>
{{item.title}}
</li>
</ul>
</template>
Шаг 2
На данном этапе реализации выбранный элемент «прилипает» к курсору и следует за ним, пока мы не отпустим его. После «сброса» элемент должен вернуться в исходное положение, так как мы не рассчитали и не сохранили его новую позицию.

Теперь необходимо сохранить обновлённые положения
Для этого создадим переменную reorderedList, в которой будем сохранять измененные данные до окончания перетаскивания. При его окончании мы присвоим reorderedList начальным элементам.
methods: {
myDrag(key, event) {
this.draggableIndex = key;
this.reorderedList = this.items;
this.moveAt(event);
},
moveAt(event){
if(this.draggableIndex !== -1){
let reorderedList=[];
let lastI = -1;
// получить отображаемые элементы списка
// и их координаты
this.$refs.li.forEach((elem, i) => {
// игнорируем перетаскиваемый элемент
if (i !== this.draggableIndex) {
if (elem.offsetTop < event.pageY
&& i > this.draggableIndex) {
// если мы здесь, то элемент переместился вверх
reorderedList[i - 1] = this.items[i];
if (lastI === -1 || lastI < i) {
lastI = i;
}
} else if (elem.offsetTop > event.pageY
&& i < this.draggableIndex) {
// если мы здесь, то элемент переместился вниз
reorderedList[i + 1] = this.items[i];
if (lastI === -1 || lastI > i) {
lastI = i;
}
} else {
//иначе его позиции не изменились
reorderedList[i] = this.items[i];
}
}
});
// если позиции изменились, мы должны переопределить элементы
if (lastI !== -1) {
reorderedList[lastI] = this.items[this.draggableIndex];
this.reorderedList = Object.assign([], reorderedList, reorderedList);
}
this.dragLeft = event.pageX - 16;
this.dragTop = event.pageY - 16;
}
},
myDragStop() {
this.draggableIndex = -1;
this.dragLeft = 0;
this.dragTop = 0;
this.items = Object.assign([], this.reorderedList, this.reorderedList);
}
...
}
Заключение
Мы получили самый простой способ реализации перетаскивания элемента!