可拖拽的select组件
发表于:2024-09-18 |

前言

最近做项目有个需求,需要 select 具有 drag 的功能,我知道他有现成的轮子,但是我想着自己做一个练练手,尝试了一下,果然还是比较简单的。这里以 vue2+element ui 和 vue3+tdesign ui 作为介绍

依赖安装

这里的拖拽我是基于 sortablejs 实现的,antd 的拖拽就是基于这个实现的

首先是 vue2+element ui

首先拿el-select作为基础架构,添加$attr$listeners监听它原来的v-bindv-on的事件。这里的el节点就是整个 select 的行
效果图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<template>
<el-select
ref="dragSelect"
v-model="selectVal"
v-bind="$attrs"
class="drag-select"
multiple
v-on="$listeners"
>
<slot />
</el-select>
</template>

<script>
import Sortable from "sortablejs";

export default {
name: "DragSelect",
props: {
value: {
type: Array,
required: true,
},
},
computed: {
selectVal: {
get() {
return [...this.value];
},
set(val) {
this.$emit("input", [...val]);
},
},
},
mounted() {
this.setSort();
},
methods: {
setSort() {
const el = this.$refs.dragSelect.$el.querySelectorAll(
".el-select__tags > span"
)[0];
this.sortable = Sortable.create(el, {
ghostClass: "sortable-ghost", // Class name for the drop placeholder,
setData: function (dataTransfer) {
dataTransfer.setData("Text", "");
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
},
onEnd: (evt) => {
const targetRow = this.value.splice(evt.oldIndex, 1)[0];
this.value.splice(evt.newIndex, 0, targetRow);
},
});
},
},
};
</script>

<style lang="scss" scoped>
.drag-select {
::v-deep {
.sortable-ghost {
opacity: 0.8;
color: #fff !important;
background: #42b983 !important;
}

.el-tag {
cursor: pointer;
}
}
}
</style>

然后是 vue3+tdesign ui

因为 vue3 中的$listeners$attrs 集成了,所以将$listeners就可以去掉了,然后父组件和子组件的v-model的绑定,我一开始使用的defineModel,发现有问题,就改成了基础的set,get的方式,其他的就和vue2的是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<template>
<t-select
ref="dragSelectRef"
v-model="modelValue"
v-bind="$attrs"
class="drag-select"
multiple
></t-select>
</template>
<script setup lang="ts">
import Sortable from "sortablejs";
import { onMounted, ref, computed } from "vue";

const props = defineProps<{
modelValue: string[];
}>();
const emit = defineEmits(["update:modelValue"]);
const modelValue = computed({
get: () => props.modelValue,
set: (val) => emit("update:modelValue", val),
});

const sortable = ref(null);

onMounted(() => {
setSort();
});
const dragSelectRef = ref();
const setSort = () => {
const el = dragSelectRef.value.$el.querySelector(".t-input__prefix");
sortable.value = Sortable.create(el, {
ghostClass: "sortable-ghost", // Class name for the drop placeholder,
setData: function (dataTransfer) {
dataTransfer.setData("Text", "");
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
},
onEnd: (evt) => {
const targetRow = modelValue.value.splice(evt.oldIndex, 1)[0];
modelValue.value.splice(evt.newIndex, 0, targetRow);
},
});
};
</script>
<style scoped lang="less">
.drag-select {
:deep(.sortable-ghost) {
opacity: 0.8;
color: #fff !important;
background: #42b983 !important;

.t-tag {
cursor: pointer;
}
}
}
</style>

效果

结语

本篇文章就到这里了,更多内容敬请期待,债见。

上一篇:
【可视化学习】88-3D后期效果(二)
下一篇:
帮后端同事爬数据记录(二)