Minimal drag and drop vue template
related: Vue
There are native browser APIs. Gotcha: It needs to be explicitly draggable="true"
. draggable
is an enum, not a boolean.
<script lang="ts" setup>
const items = ref([
{
id: 0,
title: 'Item A',
list: 1,
},
{
id: 1,
title: 'Item B',
list: 1,
},
{
id: 2,
title: 'Item C',
list: 2,
},
])
const startDrag = (evt, item) => {
evt.dataTransfer.dropEffect = 'move'
evt.dataTransfer.effectAllowed = 'move'
evt.dataTransfer.setData('itemID', item.id)
}
const onDrop = (evt, list) => {
console.log("ondrop", evt.dataTransfer.getData('itemID'), list)
const itemID = evt.dataTransfer.getData('itemID')
const item = items.value.find((item) => item.id == itemID)
if (!item) {
console.log("couldn't find item")
return
}
item.list = list
}
const listOne = computed(() => {
return items.value.filter((item) => item.list === 1)
})
const listTwo = computed(() => {
return items.value.filter((item) => item.list === 2)
})
</script>
<template lang="pug">
div
.drop-zone(@drop="onDrop($event, 1)", @dragover.prevent, @dragenter.prevent)
.drag-el(v-for='item in listOne', :key='item.title', draggable="true", @dragstart="startDrag($event, item)") {{ item.title }}
.drop-zone(@drop="onDrop($event, 2)", @dragover.prevent, @dragenter.prevent)
.drag-el(v-for='item in listTwo', :key='item.title', draggable="true", @dragstart="startDrag($event, item)") {{ item.title }}
</template>
<style scoped>
.drop-zone {
@apply bg-neutral-800;
margin-bottom: 10px;
padding: 10px;
}
.drag-el {
background-color: #fff;
margin-bottom: 10px;
padding: 5px;
}
</style>