<template>
<div class="container">
<el-transfer
ref="sortableRef"
v-model="rightData"
filterable
:filter-method="filterMethod"
filter-placeholder="请输入"
:data="data"
@change="transferChange"
>
<template #default="{ option }">
<div
class="transferLable"
:draggable="rightData.includes(option.key)"
@dragstart="handleDragStart(option)"
@dragenter="handleDragenter($event, option)"
@dragend="handleDrop($event)"
>
<span class="trnsferValue">{{ option.label }}</span>
<span id="draggable" class="sort">
<el-icon><Rank /></el-icon>
</span>
</div>
</template>
</el-transfer>
</div>
</template>
<script setup name="nurserItem">
import { ref } from "vue";
import { Rank } from "@element-plus/icons-vue";
const data = ref([
{ key: 111, label: "11" },
{ key: 122, label: "22" },
{ key: 133, label: "33" },
{ key: 144, label: "44" },
{ key: 155, label: "55" },
{ key: 166, label: "66" },
]);
const rightData = ref([]);
const filterMethod = (query, item) => {
if (!query) {
return true;
}
return item.label.includes(query);
};
// 往右侧添加时,手动添加头部
const transferChange = (_, direction, movedKeys) => {
if (direction === "right") {
const arrList = data.value.filter((item) => !movedKeys.includes(item.key));
const arrUnshift = data.value.filter((item) => movedKeys.includes(item.key));
data.value = [...arrUnshift, ...arrList];
}
console.log(
"往右侧添加时,手动添加头部 enrichedRightData.value",
enrichedRightData.value
);
// console.log("往右侧添加时,手动添加头部 data.value", data.value);
};
let dragTarget = null; // 用于存储被拖动的目标项
let dragIndex = -1; // 被拖动项在数组中的原始索引
let targetOption = null; // 拖动过程中停放目标
// 开始拖动
const handleDragStart = (option) => {
dragTarget = option;
dragIndex = data.value.findIndex((item) => item === option);
};
// 放置时重新排序数组
const handleDragenter = (event, option) => {
event.preventDefault();
if (!dragTarget || !option) return;
targetOption = option;
if (event.target.draggable) {
clearMovingDOM();
const targetIndex = data.value.findIndex((item) => item.key === targetOption.key);
if (targetIndex < dragIndex) {
// 往上拖拽
event.target.className = "movingTop";
} else {
// 往下拖拽
event.target.className = "movingBottom";
}
}
console.log("放置时重新排序数组 enrichedRightData.value", enrichedRightData.value);
};
// 鼠标放开--拖拽结束
const handleDrop = () => {
const targetIndex = data.value.findIndex((item) => item.key === targetOption.key);
const newIndex = targetIndex;
// 更新数组顺序
const [removed] = data.value.splice(dragIndex, 1);
data.value.splice(newIndex, 0, removed);
console.log("鼠标放开--拖拽结束 enrichedRightData.value", enrichedRightData.value);
// console.log("鼠标放开--拖拽结束 data.value", data.value);
// 重置拖动状态
dragTarget = null;
targetOption = null;
dragIndex = -1;
clearMovingDOM();
};
const enrichedRightData = computed(() => {
return rightData.value.map((key) => {
const item = data.value.find((d) => d.key === key); // 找到原始对象
if (!item) return { key, label: "", index: -1 }; // 防御性处理
const indexInData = data.value.findIndex((d) => d.key === key);
var r = {
key: item.key,
label: item.label,
index: indexInData,
};
console.log("enrichedRightData 执行结果", r);
return r;
});
});
// 清除moving Class名
const clearMovingDOM = () => {
document.querySelectorAll(".movingBottom").forEach((Element) => {
Element.className = "transferLable";
});
document.querySelectorAll(".movingTop").forEach((Element) => {
Element.className = "transferLable";
});
};
</script>
<style scoped>
.container {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
::v-deep(.el-transfer-panel__item).el-checkbox {
margin-right: 10px;
.transferLable {
display: flex;
justify-content: space-between !important;
}
}
.el-transfer ::v-deep(.el-transfer-panel):first-child .sort {
display: none;
}
.moving {
border-bottom: 1px solid #409eff;
}
.movingTop {
border-top: 1px solid #409eff;
}
.movingBottom {
border-bottom: 1px solid #409eff;
}
</style>