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

posted @ 2025-05-17 14:52  CrossPython  阅读(63)  评论(0)    收藏  举报