Reputation: 36311
I am building a drag and drop feature in my application where the drop area looks like this:
<template>
<div class="layers-panel" @dragover="onDragOver" @drop="onDragDrop">
<layer
v-for="(layer, index) in layers"
:key="layer.name"
:info="layer"
:offset="index"
ref="layer"
></layer>
</div>
</template>
Then the draggable items look like this:
<template>
<div class="layer" draggable="true" @dragstart="onDragStart">
<!-- Content of draggable element -->
</div>
</template>
In my drag over event, I want to get the current component that the element relates to, so when I drag an item over the <div class="layer"...>
element I would like to get that component. I am not sure how to get access to this since an event is passed to the @dragover="onDragOver"
event which only gives me access to html elements and not Vue components.
This is what my current dragover
event looks like:
public onDragOver(evt: DragEvent) {
evt.preventDefault()
if (!evt.target) return
let layer = (evt.target as HTMLElement).closest('.layer') as HTMLElement
}
How can I get the component that that element belongs to?
Upvotes: 4
Views: 2978
Reputation: 7594
Vue certainly allows you to access a component instance however I don't think it's necessary to reaching your actual goal: reordering of components via drag-and-drop.
Drag-and-drop means we're limited by what's afforded by DragEvent:
You can't determine where the element is dropped because your drop element contains all the layers. Instead if each layer is a drop element, then you can determine which one it is via dragover
via event.target
.
We also need to identify which element corresponding to the layers
array we're dragging/dropping on. This can be achieved by binding the index of each layer
as an attribute so we can access it via event.target
.
To keep it simple, I'll use the id
attribute so I can just access it later via event.target.id
:
<div
v-for="(layer, idx) in layers"
:key="idx"
:id="idx"
draggable="true"
@dragstart="dragstart"
>
<div
:id="idx"
class="draggable"
@dragover="dragover"
@drop="drop"
>
{{ layer }}
</div>
</div>
Note I bind the same index to id so I can correctly identify the target layer.
We'll also need to ensure we can identify the element that was dragged since on drop
we'll only have the drop element via event.target
. We can do this by setting data in DataTransfer
when we first start the drag:
dragstart(event) {
event.dataTransfer.setData("selectedIdx", event.target.id);
},
Now on drop we have access to both and can manipulate layers
as we desire:
drop(event) {
var selectedIdx = event.dataTransfer.getData("selectedIdx");
var targetIdx = event.target.id;
var selected = this.layers.splice(selectedIdx, 1)[0];
this.layers.splice(targetIdx, 0, selected);
},
Upvotes: 2