You want to do a couple of things. The default ghost image is something that the browser does by default. We can't make that opaque though, so we want to get rid of it. To do this, listen to the dragstart event, and set the drag image to an empty image:
event.dataTransfer.setDragImage(new Image(), 0, 0);
Now that we have that out of the way, we need to make the dragged image. To both get an indication of where the item will be dropped, and the actual card you are dropping, I think you can best just duplicate the card that is being moved into a temporary container that you can manipulate. You then figure out where the mouse is and move the temporary container around. At the end you want to remove the temporary card, so you don't end up with a random card somewhere on the screen.
Your template would look something like this:
<draggable v-model="items" animation="150">
<div
v-for="item in items"
:key="item"
class="item"
@dragstart="dragStartHandler"
@dragend="dragEndHandler"
@drag="dragHandler"
>{{ item }}</div>
</draggable>
<div class="drag-preview" :style="dragStyle" ref="dragPreview"></div>
We can use dragstart and dragend to both set the empty placeholder, and add and remove a duplicated card
dragStartHandler(e) {
this.dragPreview = e.target.cloneNode(true);
this.$refs["dragPreview"].appendChild(this.dragPreview);
e.dataTransfer.setDragImage(new Image(), 0, 0);
},
dragEndHandler() {
this.dragPreview.remove();
this.dragPreview = null;
},
The drag event is an extended MouseEvent, which has screen and page coordinates. We listen to it to figure out where the mouse is, and just update some variables with them.
dragHandler(e) {
this.x = e.pageX;
this.y = e.pageY;
}
You can then compute your top and left coordinates, by simply appending px to them
dragStyle() {
return {
top: `${this.y}px`,
left: `${this.x}px`
};
}
To style this all, the item that is currently being sorted has the sortable-ghost class by default. In my case, I just gave it a gray dashed outline, and set the font-size to 0 to hide the text.
.sortable-ghost {
border: 1px dashed grey;
font-size: 0;
overflow: hidden;
}
The drag-preview class is what follows the mouse around. Of course, nothing is in there when you are not dragging anything. Your example shows a slightly tilted card, so we translate the card 50% to the top and left, so it is centered on our mouse. We then rotate it slightly by 7 degrees. Finally we move it down by 55% so it does not intersect with our mouse.
.drag-preview {
position: absolute;
transform: translateX(-50%) translateY(-50%) rotate(7deg) translateY(55%);
}
