怎么用vue实现拖拽排序效果
本篇内容介绍了“怎么用vue实现拖拽排序效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
效果预览
组件 drag.vue
<template>
<TransitionGroup name="group-list" tag="ul">
<li
v-for="(item, index) in list"
:key="item.name"
:draggable="item.draggable"
:class="[
'list-item',
{
'is-dragover':
index === dropIndex && item.draggable && config.exchange,
},
]"
@dragstart="onDragstart($event, index)"
@dragenter="onDragenter(index)"
@dragover.prevent="onDragover(index)"
@dragleave="onDragleave"
@dragend="onDragend"
@drop="onDrop"
>
<slot :item="item" />
</li>
</TransitionGroup>
</template>
<script>
export default {
name: "Draggable",
props: {
list: {
type: Array,
default: () => [],
},
config: {
type: Object,
default: () => ({
name: "",
push: true,
pull: true,
exchange: true,
}),
},
},
data() {
return {
dragIndex: null,
dropIndex: null,
};
},
computed: {
isPush() {
const { dropIndex, dragIndex } = this;
return dropIndex !== null && dragIndex === null;
},
isExchange() {
const { dropIndex, dragIndex } = this;
return dragIndex !== null && dropIndex !== null;
},
pushCbName() {
const {
config: { name },
} = this;
return `${name}-push-callback`;
},
},
methods: {
onDragstart(e, i) {
const {
list,
config: { name },
transferData,
} = this;
this.dragIndex = i;
if (name) {
transferData({ e, key: name, type: "set", data: list[i] });
} else {
throw new Error("缺少配置关联名name");
}
this.$emit("drag-start", i);
},
onDragenter(i) {
this.dropIndex = i;
this.$emit("drag-enter", i);
},
onDragover(i) {
const { dragIndex, dropIndex } = this;
if (i === dragIndex || i === dropIndex) return;
this.dropIndex = i;
this.$emit("drag-over", i);
},
onDragleave() {
this.dropIndex = null;
},
onDrop(e) {
const {
list,
dropIndex,
dragIndex,
config: { name, push: enablePush, exchange },
isPush,
isExchange,
pushCbName,
storage,
resetIndex,
transferData,
} = this;
if (dropIndex === dragIndex || !exchange) return;
if (isPush) {
if (!enablePush) {
resetIndex();
return;
}
if (name) {
list.splice(
dropIndex,
0,
transferData({ e, key: name, type: "get" })
);
storage("set", pushCbName, true);
} else {
resetIndex();
throw new Error("缺少配置关联属性name");
}
resetIndex();
return;
}
if (isExchange) {
const drapItem = list[dragIndex];
const dropItem = list[dropIndex];
list.splice(dropIndex, 1, drapItem);
list.splice(dragIndex, 1, dropItem);
}
resetIndex();
},
onDragend() {
const {
list,
dragIndex,
config: { pull: enablePull },
pushCbName,
storage,
resetIndex,
} = this;
if (enablePull) {
const isPushSuccess = storage("get", pushCbName);
if (isPushSuccess) {
list.splice(dragIndex, 1);
storage("remove", pushCbName);
}
}
resetIndex();
this.$emit("drag-end");
},
storage(type, key, value) {
return {
get() {
return JSON.parse(localStorage.getItem(key));
},
set() {
localStorage.setItem(key, JSON.stringify(value));
},
remove() {
localStorage.removeItem(key);
},
}[type]();
},
resetIndex() {
this.dropIndex = null;
this.dragIndex = null;
},
transferData({ e, key, type, data } = {}) {
if (type === "get") {
return JSON.parse(e.dataTransfer.getData(`${key}-drag-key`));
}
if (type === "set") {
e.dataTransfer.setData(`${key}-drag-key`, JSON.stringify(data));
}
},
},
};
</script>
<style scoped>
.list-item {
list-style: none;
position: relative;
margin-bottom: 10px;
border-radius: 4px;
padding: 4px;
background-color: #fff;
cursor: move;
}
.list-item.is-dragover::before {
content: "";
position: absolute;
bottom: -4px;
left: 0;
width: 100%;
height: 4px;
background-color: #0c6bc9;
}
.list-item.is-dragover::after {
content: "";
position: absolute;
bottom: -8px;
left: -6px;
border: 3px solid #0c6bc9;
border-radius: 50%;
width: 6px;
height: 6px;
background-color: #fff;
}
.group-list-move {
transition: transform 0.8s;
}
</style>
使用范例
index.vue
<template>
<div class="dragBox">
<Drag :list="list1" :config="config1">
<template v-slot="{ item }">
<div class="item">
{{ item.name }}
</div>
</template>
</Drag>
<Drag :list="list2" :config="config2">
<template v-slot="{ item }">
<div class="item">
{{ item.name }}
</div>
</template>
</Drag>
</div>
</template>
<script>
import Drag from "./drag.vue";
export default {
components: {
Drag,
},
data() {
return {
list1: new Array(10).fill(0).map((_, i) => ({
name: `列表1 - ${i + 1}`,
draggable: true,
})),
config1: {
name: "test",
push: true,
pull: true,
exchange: true,
},
list2: new Array(10).fill(0).map((_, i) => ({
name: `列表2 - ${i + 1}`,
draggable: true,
})),
config2: {
name: "test",
push: true,
pull: true,
exchange: true,
},
};
},
};
</script>
<style scoped>
.dragBox {
display: flex;
justify-content: center;
}
.item {
border: 1px solid #ccc;
width: 200px;
height: 30px;
text-align: center;
}
</style>
参数说明
list: 渲染列表
config: {
name: '', // 跨列表关联名,跨列表拖拽时必传
push: true, // 当前列表是否支持从其他列表push元素进来
pull: true, // 将当前列表的某个元素拖拽并添加到其他列表里,该元素是否从当前列表移除
exchange: true, // 当前列表元素之间是否支持交换位置
}
相关文章