Vue based list drag sort effect

In daily development, especially on the management side, we often encounter the effect of drag-and-drop sorting. Here is a simple implementation scheme.

First, let’s take a look at javascript native drag events:

Trigger an event on a drag target (source element):

  • Ondragstart – Triggered when the user starts dragging elements
  • Ondrag – Triggered while the element is dragging
  • Ondragend – Triggered when the user finishes dragging the element

Events that trigger when a target is released:

  • Ondragenter – This event is triggered when a mouse-dragged object enters its container scope
  • Ondragover – This event is triggered when a dragged object is dragged within the scope of another object container
  • Ondragleave – This event is triggered when an object dragged by the mouse leaves its container scope
  • Ondrop – This event is triggered when the mouse key is released during a drag


Based on js native drag events, the principle of drag sorting implemented this time is probably as follows: The onDragStart event is triggered when the mouse holds down an item in the list to start dragging, and the drag item is recorded with variables; And then during the drag process, when the drag item passes another item on the list, the onDragEnter event is triggered, and the data of the last item on the list that the drag item passes is also recorded, and finally in the onDragEnd event, the arraylist is deleted from the drag item recorded in the original onDragStart event, Insert the deleted data into the last recorded position of the onDragEnter event to complete the drag sorting.


The specific code is as follows:

<template>
    <div class="test_wrapper" @dragover="dragover($event)">
        <transition-group class="transition-wrapper" name="sort">
            <div v-for="(item) in dataList" :key='item.id' class="sort-item"
                :draggable="true"
                @dragstart="dragstart(item)"
                @dragenter="dragenter(item,$event)"
                @dragend="dragend(item,$event)"
                @dragover="dragover($event)"
            >
                {{ item.label }}
            </div>
        </transition-group>
    </div>
</template>

<script lang="ts">
    import {Vue, Component, Prop, Watch} from "vue-property-decorator";
    import { addWebsite } from '@/api'
    @Component({
        components: {}})export default class Test extends Vue {

        oldData: any = null; // Hold down the old data to start sorting
        newData: any = null; // Drag process data

        // List data
        dataList:any = [
            { id:1.label:'Test One' },
            { id:2.label:'Test Two' },
            { id:3.label:'Test Number three' },
            { id:4.label:'Test 4'},];dragstart(value: any) {
            this.oldData = value
        }

        // Record information during movement
        dragenter(value: any, e: any) {
            this.newData = value
            e.preventDefault()
        }

        // Drag the final operation
        dragend(value: any, e: any) {
            if (this.oldData ! = =this.newData) {
                let oldIndex = this.dataList.indexOf(this.oldData)
                let newIndex = this.dataList.indexOf(this.newData)
                let newItems = [...this.dataList]
                // Delete the old node
                newItems.splice(oldIndex, 1)
                // Add a new node to the list at the target location
                newItems.splice(newIndex, 0.this.oldData)
                this.dataList = [...newItems]
            }
        }


        // Drag events (mainly so that the mouse cursor does not become disabled when dragging)
        dragover(e: any) {
            e.preventDefault()
        }


    };
</script>
Copy the code


In addition

To animate the drag, use the transition-group component. As shown above, set the transition-group attribute name to ‘sort’. Add the following code;

        .sort-move {
            transition: transform 0.3 s;
        }
Copy the code

Note: In order for the transition to work, the v-for rendering must have a key attribute that cannot be set to index.


The final effect is as follows: