Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get vue component from event

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?

like image 732
Get Off My Lawn Avatar asked Oct 19 '25 01:10

Get Off My Lawn


1 Answers

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:

  • We can access the target element e.g. the element being dragged or dropped on
  • We can set arbitrary data via DataTransfer

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);
},

Example codepen

like image 77
xlm Avatar answered Oct 20 '25 14:10

xlm



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!