Custom drag preview

In the previous chapter, you probably already noticed that the pointer event provider has a few caveats.

For example,

  • you can't drag the item out of the scroll container
  • the original place doesn't have a placeholder item there

The vue dnd has a mechanism for you to customize this behavior.

Setup

Before adding the preview, we need a container to contain the preview we want to render.

Due to css overflow containers, this container is preferred to be put in the <body> root.

This can be done with the vue <Teleport>

<!-- app.vue-->
<template>
    <Box
        v-for="box in boxes"
        :index="box.id"
        :key="box.id"
        @drop="onDrop"
    >
        <Ball
            v-for="item in box.items"
            :key="item"
            :from="box.id"
            :index="item"
        ></Ball>
    </Box>
    <Teleport to="body">
        <DragLayer />
    </Teleport>
</template>
<script setup lang="ts">
import { DrayLayer } from '@mmis1000/vue-dnd'
/* ... */
</script>
<style>
/* ... */
</style>















 
 
 


 





Add preview to drag target

And now we add drag preview to drag target

import { computed, h } from "vue";
import { useDraggable } from '@mmis1000/vue-dnd';
import { BallType } from "./type";
import { BallPreview } from "./ball-preview";

const props = defineProps({
    from: {
        type: String,
        required: true,
    },
    index: {
        type: String,
        required: true,
    }
});

const { propsItem, state } = useDraggable(
    BallType,
    computed<[string, string]>(() => [props.index, props.from]),
    {
        preview: () => {
            return h(BallPreview, { index: props.index })
        }
    }
);



 















 
 
 
 
 

import { computed } from "vue";
import { useDraggable } from '@mmis1000/vue-dnd';
import { BallType } from "./type";
import { BallPreview } from "./ball-preview";

const props = defineProps({
    from: {
        type: String,
        required: true,
    },
    index: {
        type: String,
        required: true,
    }
});

const { propsItem, state } = useDraggable(
    BallType,
    computed<[string, string]>(() => [props.index, props.from]),
    {
        preview: () => {
            return <BallPreview index={props.index} />
        }
    }
);



 















 
 
 
 
 

The preview can be in whatever component you wish, but it must not cause side effects because it may be re-rendered at any time.

Result

example Source