指尖上的记忆指尖上的记忆
首页
  • 基础
  • Laravel框架
  • Symfony框架
  • 基础
  • Gin框架
  • 基础
  • Spring框架
  • 命令
  • Nginx
  • Ai
  • Deploy
  • Docker
  • K8s
  • Micro
  • RabbitMQ
  • Mysql
  • PostgreSsql
  • Redis
  • MongoDb
  • Html
  • Js
  • 前端
  • 后端
  • Git
  • 知识扫盲
  • Golang
🌟 gitHub
首页
  • 基础
  • Laravel框架
  • Symfony框架
  • 基础
  • Gin框架
  • 基础
  • Spring框架
  • 命令
  • Nginx
  • Ai
  • Deploy
  • Docker
  • K8s
  • Micro
  • RabbitMQ
  • Mysql
  • PostgreSsql
  • Redis
  • MongoDb
  • Html
  • Js
  • 前端
  • 后端
  • Git
  • 知识扫盲
  • Golang
🌟 gitHub

封装一个vue3的表格拖拽功能:

1.在utils下创建dragDropManager.ts
interface DragConfig {
  draggableColumns?: string[]; // 可拖拽列的名称
  undraggableRows?: number[];  // 禁止拖拽的行索引
}
  
export class TableDragManager<T> {
  private list: T[]; // 数据源
  private config: DragConfig; // 拖拽配置
  private draggingIndex: number | null = null; //当前拖动元素的索引
  private onDropCallback?: (draggedId: number, newList: any[]) => void; //回调
  
  constructor(list: T[], config: DragConfig) {
    this.list = list;
    this.config = config;
  }
  
  // 设置拖拽完成之后的回调方法,用于调用API,保存拖拽之后的数据
  setOnDropCallback(callback: (draggedId: number, newList: any[]) => void) {
    this.onDropCallback = callback;
  }
  
  onDragStart(index: number, column: string | null, event: DragEvent): void {
    if (this.config.undraggableRows?.includes(index)) {
      event.preventDefault();
      return;
    }
  
    if (column && this.config.draggableColumns && !this.config.draggableColumns.includes(column)) {
      event.preventDefault();
      return;
    }
  
    this.draggingIndex = index;
  }
  
  // targetIndex: 将要拖动到的位置的索引  event: 拖拽事件  canDrop:用于判断能否拖拽到指定位置(因为有些行不允许拖拽,也就意味着别的行也不能拖拽到对应位置)
  onDrop(targetIndex: number, event: DragEvent, canDrop: (index: number) => boolean): void {
    event.preventDefault();
  
    console.log("targetIndex is:", targetIndex);
    console.log("draggingIndex is:", this.draggingIndex);
  
    if (this.draggingIndex !== null && this.draggingIndex !== targetIndex && canDrop(targetIndex)) {
      const draggedItem = this.list[this.draggingIndex];
      this.list.splice(this.draggingIndex, 1);
      this.list.splice(targetIndex, 0, draggedItem);
  
      if (this.onDropCallback) {
        this.onDropCallback(draggedItem.id, this.list);
      }
    }
  
    this.draggingIndex = null;
  }
  
  onDragOver(event: DragEvent): void {
    event.preventDefault(); // 必须阻止默认行为以允许放置
  }
}
  
2.在vue3页面test.vue调用
1>禁止部分行拖拽以及指定字段可拖拽
<script setup lang="ts">
import { TableDragManager } from '~/utils/dragDropManager';
  
interface TableRow {
  id: number;
  name: string;
  age: number;
}
  
const list = ref<TableRow[]>([
  { id: 1, name: 'Row 1', age: 25 },
  { id: 2, name: 'Row 2', age: 30 },
  { id: 3, name: 'Row 3', age: 35 },
  { id: 4, name: 'Row 4', age: 55 },
]);
  
// 配置
const config = {
  draggableColumns: ['id'], // 仅允许 ID 列拖拽
  undraggableRows: [0,1],     // 第 0 1 行禁止拖拽 (默认按顺序禁止)
};
  
// 实例化拖拽管理器
const dragManager = new TableDragManager(list.value, config);
  
const canDrop = (index: number) => {
  
  // 禁止前两行行拖拽
  if (config.undraggableRows && index < config.undraggableRows.length) {
    return false;
  }
  return true;
};
  
const handleDrop = (draggedId: number, newList: any[]) => {
  console.log("draggedId is:", draggedId);
  console.log("newList is:", newList);
}
  
onMounted(() => {
  dragManager.setOnDropCallback(handleDrop);
});
</script>
  
<template>
  <table>
    <thead>
    <tr>
      <th>ID</th>
      <th>Name</th>
      <th>Age</th>
    </tr>
    </thead>
    <tbody>
    <tr
      v-for="(row, index) in list"
      :key="row.id"
    >
      <td
        :draggable="true"
        @dragstart="dragManager.onDragStart(index, 'id', $event)"
        @dragover="dragManager.onDragOver($event)"
        @drop="dragManager.onDrop(index, $event, canDrop)"
      >
        {{ row.id }}
      </td>
      <td>{{ row.name }}</td>
      <td>{{ row.age }}</td>
    </tr>
    </tbody>
  </table>
</template>

2>常规拖拽(没有任何限制)
<script setup lang="ts">
import { TableDragManager } from '~/utils/dragDropManager';
  
interface TableRow {
  id: number;
  name: string;
  age: number;
}
  
const list = ref<TableRow[]>([
  { id: 1, name: 'Row 1', age: 25 },
  { id: 2, name: 'Row 2', age: 30 },
  { id: 3, name: 'Row 3', age: 35 },
  { id: 4, name: 'Row 4', age: 55 },
]);
  
// 配置
const config = {
  draggableColumns: [], // 仅允许 ID 列拖拽
  undraggableRows: [],     // 第 0 1 行禁止拖拽 (默认按顺序禁止)
};
  
// 实例化拖拽管理器
const dragManager = new TableDragManager(list.value, config);
  
const canDrop = (index: number) => {

  // 禁止前两行行拖拽
  if (config.undraggableRows && index < config.undraggableRows.length) {
    return false;
  }
  return true;
};
  
const handleDrop = (draggedId: number, newList: any[]) => {
  console.log("draggedId is:", draggedId);
  console.log("newList is:", newList);
}
  
onMounted(() => {
  dragManager.setOnDropCallback(handleDrop);
});
</script>
  
<template>
  <table>
    <thead>
    <tr>
      <th>ID</th>
      <th>Name</th>
      <th>Age</th>
    </tr>
    </thead>
    <tbody>
    <tr
      v-for="(row, index) in list"
      :key="row.id"
      :draggable="true"
      @dragstart="dragManager.onDragStart(index, null, $event)"
      @dragover="dragManager.onDragOver($event)"
      @drop="dragManager.onDrop(index, $event, canDrop)"
    >
      <td
      >
        {{ row.id }}
      </td>
      <td>{{ row.name }}</td>
      <td>{{ row.age }}</td>
    </tr>
    </tbody>
  </table>
</template>
  
3>关于splice的使用分析
//
let lists = ['A', 'B', 'C', 'D'];
// 假设要把 'B' 移动到 'D' 前面
  
// 1. 保存 'B'
const draggedItem = lists[1]; // 'B'
  
// 2. 删除索引1的 'B'
lists.splice(1, 1); // list 现在是 ['A', 'C', 'D']
  
// 3. 在索引2处插入 'B'
lists.splice(2, 0, draggedItem); // list 变成 ['A', 'C', 'B', 'D']