element ui plus 穿梭框 拖动排序
<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>