preface

In business, list drag sorting is a common requirement. Common JS drag libraries include sortable. JS, vue. Draggable, etc. Most students also turn to these JS libraries for help when meeting such requirements. In combination with Vue’s transition-group, you can also quickly add transition animations to sorts.

HTML 5 drag and drop API

Set elements to drag-and-drop

To enable an element to be dragged and dropped, the draggable attribute is set to True (default for text, images, and links is true).

<div draggable="true">Elements that can be dragged and dropped</div>
Copy the code

Drag and drop event

Drag and drop involves two types of elements: the dragged element (the source object) and the drop element (the target object). As shown in the figure below, hold down element A and drag it to element B. Element A is the source object and element B is the target object.

Different objects generate different drag-and-drop events.

Triggered objects The name of the event instructions
The source object dragstart Triggered when the source object starts to be dragged
drag The source object is fired repeatedly while dragging
dragend Triggered when the source object is finished dragging
The target object dragenter Trigger when the source object starts to enter the target object scope
dragover Fired when the source object moves within the scope of the target object
dragleave Triggered when the source object leaves the target object scope
drop Emitted when the source object is released within the scope of the target object

Note that the default behavior of the Dragenter and dragover events is to refuse to accept any dragged elements. Therefore, use preventDefault on these two drag-and-drop events to prevent the browser’s default behavior; And for the target object to become releasable, the dragover and DROP event handler properties must be set.

There are a few other properties and methods for drag and drop, but for what we’re going to do today, you just need to master the properties and methods mentioned above. If you want to explore them further, you can refer to the HTML drag and drop API

Drag and drop the sorting

Below we use drag and drop API to achieve a list of drag and drop sort, code based on Vue implementation.

Forget about sorting animations for a second. The code is not complicated, so I posted it all and explained how to implement it:

  1. Since dragging is real-time, it is not useddropI’m usingdragenterTrigger sort.
  2. Records the index of the source object when it starts to be draggeddragIndex, when it enters the target object (correspondingdragenterEvent), inserts it into the position of the target object.
  3. Among themdragenterThere is a judgment in the methodthis.dragIndex ! == indexIndex is the index of the current target objectThe source object is also the target objectIn the absence of this judgment, the source object will trigger its own immediately when it starts to be draggeddragenterEvent, this is unreasonable.

The final effect is as follows:

<template>
  <ul class="list">
    <li
      @dragenter="dragenter($event, index)"
      @dragover="dragover($event, index)"
      @dragstart="dragstart(index)"
      draggable
      v-for="(item, index) in list"
      :key="item.label"
      class="list-item"
     >
      {{item.label}}
    </li>
  </ul>
</template>
<script>
export default {
  data() {
    return {
      list: [{label: List of '1' },
        { label: List of '2' },
        { label: List of '3' },
        { label: 'list 4' },
        { label: List of '5' },
        { label: 'list 6'},].dragIndex: ' '.enterIndex: ' '}; },methods: {
    dragstart(index) {
      this.dragIndex = index;
    },
    dragenter(e, index) {
      e.preventDefault();
      // Prevent the source object from firing its own dragenter event
      if (this.dragIndex ! == index) {const source = this.list[this.dragIndex];
        this.list.splice(this.dragIndex, 1);
        this.list.splice(index, 0, source);
        // The index of the target object becomes the index of the source object
        this.dragIndex = index; }},dragover(e, index){ e.preventDefault(); ,}}};</script>
<style lang="scss" scoped>
.list {
  list-style: none;
  .list-item {
    cursor: move;
    width: 300px;
    background: #EA6E59;
    border-radius: 4px;
    color: #FFF;
    margin-bottom: 6px;
    height: 50px;
    line-height: 50px;
    text-align: center; }}</style>
Copy the code

Subtracting HTML and CSS, the core dragenter has no more than 15 lines of code to implement a drag-and-sort function. Of course, this drag-and-drop effect is a bit stiff, so let’s use the transition-group component that comes with Vue to add a smooth transition effect to sorting.

Sort the animation

If you are not familiar with transition-group of Vue, please learn the sorting transition of Vue list first.

Change the ul element of HTML to transition-group, add the shuffle method to methods, and add a transition to CSS: transform .3s; Now you can implement the drag-and-drop sort effect shown in the first image.

You can try it online by clicking on this link.

<template>
  <div>
    <transition-group
      name="drag"
      class="list"
      tag="ul"
    >
      <li
        @dragenter="dragenter($event, index)"
        @dragover="dragover($event, index)"
        @dragstart="dragstart(index)"
        draggable
        v-for="(item, index) in list"
        :key="item.label"
        class="list-item">
        {{item.label}}
      </li>
    </transition-group>
  </div>
</template>
<script>
export default {
  data() {
    return {
      list: [{label: List of '1' },
        { label: List of '2' },
        { label: List of '3' },
        { label: 'list 4' },
        { label: List of '5' },
        { label: 'list 6'},].dragIndex: ' '.enterIndex: ' '}; },methods: {
    shuffle() {
      this.list = this.$shuffle(this.list);
    },
    dragstart(index) {
      this.dragIndex = index;
    },
    dragenter(e, index) {
      e.preventDefault();
      // Prevent the source object from firing its own dragenter event
      if (this.dragIndex ! == index) {const moving = this.list[this.dragIndex];
        this.list.splice(this.dragIndex, 1);
        this.list.splice(index, 0, moving);
        // The index of the target object becomes the index of the source object
        this.dragIndex = index; }},dragover(e, index){ e.preventDefault(); ,}}};</script>
<style lang="scss" scoped>
.list {
  list-style: none;
  .drag-move {
    transition: transform .3s;
  }
  .list-item {
    cursor: move;
    width: 300px;
    background: #EA6E59;
    border-radius: 4px;
    color: #FFF;
    margin-bottom: 6px;
    height: 50px;
    line-height: 50px;
    text-align: center; }}</style>
Copy the code

If you want to use native JS to implement drag sorting and transition animation for lists, see this article: JS Drag drag sorting