element ui plus 穿梭框实现拖动排序
<template> <div class="container"> <el-transfer ref="transferRef" v-model="dataValue" :titles="['可选字段', '已选字段']" :data="transferData" @left-check-change="leftCheckChange" @right-check-change="rightCheckChange" > <template #default="{ option }"> <span :draggable="!option.disabled" @dragstart="drag($event, option)"> {{ option.label }} </span> </template> </el-transfer> </div> </template> <script setup lang="ts"> import { onMounted, ref } from "vue"; import Sortable, { SortableEvent } from "sortablejs"; import type { TransferInstance, TransferKey, } from "element-plus/es/components/transfer/index.mjs"; interface Option { key: string; label: string; disabled: boolean; } //初始化 const generateData = () => { const data: Option[] = []; for (let i = 1; i <= 10; i++) { data.push({ key: i + "", label: `Option ${i}`, // disabled: i % 4 === 0, disabled: false, }); } return data; }; const transferData = ref<Option[]>(generateData()); const transferRef = ref<TransferInstance>(); const draggingKey = ref<string>(""); const dataValue = ref<string[]>(["1", "2"]); const transferRightCheckData = ref<string[]>([]); const transferLeftCheckData = ref<string[]>([]); const leftCheckChange = (val: TransferKey[]) => { // 穿梭框左侧多选选中 transferLeftCheckData.value = [...val] as []; console.log("穿梭框左侧多选选中", val); }; const rightCheckChange = (val: TransferKey[]) => { // 穿梭框右侧多选选中 transferRightCheckData.value = [...val] as []; console.log("穿梭框右侧多选选中", val); }; const drag = (ev: DragEvent, option: Option) => { // 赋值当前拖拽的唯一标识 draggingKey.value = option.key; console.log("drag => ev", ev); console.log("draggingKey", draggingKey.value); }; onMounted(() => { const transferEl = transferRef.value?.$el; if (!transferEl) return; const leftPanel = transferEl .getElementsByClassName("el-transfer-panel")[0] .getElementsByClassName("el-transfer-panel__body")[0]; const rightPanel = transferEl .getElementsByClassName("el-transfer-panel")[1] .getElementsByClassName("el-transfer-panel__body")[0]; const rightEl = rightPanel.getElementsByClassName("el-transfer-panel__list")[0]; Sortable.create(rightEl, { onEnd: (evt: SortableEvent) => { const { oldIndex, newIndex } = evt; const temp = dataValue?.value?.[oldIndex]; if (!temp || temp === "undefined") { return; } // 解决右边最后一项从右边拖左边,有undefined的问题 if (dataValue?.value && oldIndex != null && newIndex != null) { dataValue.value[oldIndex] = dataValue?.value[newIndex]; dataValue.value[newIndex] = temp; } }, }); const leftEl = leftPanel.getElementsByClassName("el-transfer-panel__list")[0]; Sortable.create(leftEl, { onEnd: (evt: SortableEvent) => { const { oldIndex, newIndex } = evt; const temp = transferData?.value[oldIndex]; if (!temp || temp === "undefined") { return; } // 解决右边最后一项从左边拖右边,有undefined的问题 if (transferData?.value && oldIndex != null && newIndex != null) { transferData.value[oldIndex] = transferData.value[newIndex]; transferData.value[newIndex] = temp; } }, }); leftPanel.ondragover = (ev: DragEvent) => { ev.preventDefault(); }; leftPanel.ondrop = (ev: DragEvent) => { ev.preventDefault(); // 往左拉 const index = dataValue?.value?.indexOf(draggingKey?.value); if (index !== -1) { // 如果当前拉取的是选中数据就将所有选中的数据拉到左边选中框内 if (transferRightCheckData?.value?.indexOf(draggingKey?.value) !== -1) { // 此处为多选执行 transferRightCheckData?.value?.reduce((arr, item) => { if (arr?.indexOf(item) !== -1) { // 每次计算将相同的删掉 arr?.splice(arr?.indexOf(item), 1); } return arr; }, dataValue.value); transferRightCheckData.value = []; // 清除右侧选中的 不然下次向左拉取时会有缓存 // 否则就只拉取当前一个 } else { dataValue?.value?.splice(index, 1); } } }; rightPanel.ondragover = (ev: DragEvent) => { ev.preventDefault(); }; rightPanel.ondrop = (ev: DragEvent) => { ev.preventDefault(); // 右边框里没有当前key值的时候 向右拉 if (dataValue?.value?.indexOf(draggingKey?.value) === -1) { // 此处为多选执行 // 如果当前拉取的是选中数据就将所有选中的数据拉到右边选中框内 if (transferLeftCheckData?.value?.indexOf(draggingKey?.value) !== -1) { dataValue.value = dataValue?.value?.concat(transferLeftCheckData.value); transferLeftCheckData.value = []; // 清除左侧选中的 不然下次向右拉取时会有缓存 } else { // 否则就只拉取当前一个 dataValue?.value?.push(draggingKey?.value); } } }; }); </script> <style> .container { display: flex; justify-content: center; /* 水平居中 */ align-items: center; /* 垂直居中 */ } </style>
https://blog.csdn.net/qq_43771593/article/details/147010069