vue3 拖动排序组件,拿来即用

393 阅读1分钟

介绍

本来想用vuedraggable的,但是项目一直报错,想着用到的功能只是简单的拖动排序,所以自己写一个。
此组件不影响原来的布局。

备注:
wrapClass:之前的容器class
item插槽里面放原来需要遍历的元素

用法

// 使用组件
<template>
    <Draggable v-model="list" wrapClass="wrap">
            <template #item="item">
                  <!-- 这是list的item -->
                  {{item}}
            </template>
    </Draggable>
</template>

<script lang="ts" setup>
// 引入组件
import Draggable from "@/components/Draggable/index.vue";
import { ref } from "vue"

const list = ref([{name:1,id:1},{name:2,id:2}]);
</script>
<style lang="scss" scoped>
.wrap{
    display:flex; 
}
</style>
<template>
    <TransitionGroup name="draggable" tag="div" class="draggable-wrap" :class="wrapClass ? wrapClass : ''">
        <div v-for="(item, i) in list" :key="item.id" :draggable="props.drag" @dragstart="dragstart($event, i)"
            @dragenter="dragenter($event, i)" @dragend="dragend" @dragover="dragover">
            <slot name="item" :item="item"></slot>
        </div>
    </TransitionGroup>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'

const emit = defineEmits(["update:modelValue"]);
const props = withDefaults(
    defineProps<{
        modelValue: any, // 排序列表
        wrapClass?: any, // 列表类
        drag?: boolean // 是否开启拖动,默认开启
    }>(),
    {
        modelValue: [],
        wrapClass: "",
        drag: true,
    }
);
const list = ref<any>([])
watch(() => props.modelValue, () => {
    list.value = props.modelValue
}, {
    immediate: true
})

let dragIndex = 0
let timeout: any = null

function dragstart(e, index) {
    e.stopPropagation()
    dragIndex = index
    setTimeout(() => {
        e.target.classList.add('moveing')
    }, 0)
}
function dragenter(e, index) {
    e.preventDefault()
    // 拖拽事件的防抖  必须防抖不然频繁触发会导致index值不准
    timeout = setTimeout(() => {
      if (dragIndex !== index) {
        const source = list.value[dragIndex];
        list.value.splice(dragIndex, 1);
        list.value.splice(index, 0, source);
        dragIndex = index;
        emit("update:modelValue", list);
     }
  }, 50);
}
function dragover(e) {
    e.preventDefault()
    e.dataTransfer.dropEffect = 'move'
}
function dragend(e) {
    e.target.classList.remove('moveing')
}
</script>
 
<style lang="scss" scoped>
.draggable-wrap {
    position: relative;
    padding: 0;
}

.moveing {
    opacity: 0;
}

.draggable-move,
.draggable-enter-active,
.draggable-leave-active {
    transition: all 0.2s ease;
}
</style>