Vue + Element UI el-table + sortablejs 行、列拖拽排序

实现Element UI中的el-table表格组件的行和列的拖拽排序

使用 Vue3 + Element Plus UI + sortablejs

安装sortablejs

sh 复制代码
pnpm install sortablejs

行拖拽

基本实现

效果

html 复制代码
<script setup>
import { onMounted, ref } from "vue";
import Sortable from "sortablejs";

const tableData = ref([
  {
    id: 1,
    date: "2016-05-02",
    name: "王小虎111",
    age: 21,
    address: "上海市普陀区金沙江路 1518 弄",
  },
  {
    id: 2,
    date: "2016-05-04",
    name: "王小虎222",
    age: 22,
    address: "上海市普陀区金沙江路 1517 弄",
  },
  {
    id: 3,
    date: "2016-05-01",
    name: "王小虎333",
    age: 23,
    address: "上海市普陀区金沙江路 1519 弄",
  },
  {
    id: 4,
    date: "2016-05-03",
    name: "王小虎444",
    age: 24,
    address: "上海市普陀区金沙江路 1516 弄",
  },
  {
    id: 5,
    date: "2016-05-08",
    name: "王小虎555",
    age: 25,
    address: "上海市普陀区金沙江路 1518 弄",
  },
]);

onMounted(() => {
  rowDrop();
});

/**
 * 行拖拽排序
 */
function rowDrop() {
  // 要侦听拖拽响应的DOM对象
  const tbody = document.querySelector(".el-table__body-wrapper tbody");
  const data = tableData.value;
  Sortable.create(tbody, {
    // handle: ".el-icon-rank",
    ghostClass: "target-row-class",
    // 结束拖拽后的回调函数
    onEnd({ newIndex, oldIndex }) {
      // 将oldIndex位置的数据删除并取出,oldIndex后面位置的数据会依次前移一位
      const currentRow = data.splice(oldIndex, 1)[0];
      // 将被删除元素插入到新位置(currRow表示上面的被删除数据)
      data.splice(newIndex, 0, currentRow);
    },
  });
}
</script>

<template>
  <el-table
    ref="table"
    :data="tableData"
    style="width: 100%"
    border
    row-key="id"
  >
    <el-table-column prop="date" label="日期" />
    <el-table-column prop="name" label="姓名" />
    <el-table-column prop="age" label="年龄" />
    <el-table-column prop="address" label="地址" />
    <!--<el-table-column align="center" width="55">-->
    <!--  <i class="el-icon-rank" />-->
    <!--</el-table-column>-->
  </el-table>
</template>

<style scoped lang="less">
.el-table {
  ::v-deep {
    .target-row-class {
      background: #f0f9eb;
    }
  }
}
</style>

禁止某几行拖拽

效果

html 复制代码
<script setup>
import { onMounted, ref } from "vue";
import Sortable from "sortablejs";

const tableData = ref([
  {
    id: 1,
    date: "2016-05-02",
    name: "王小虎111",
    age: 21,
    address: "上海市普陀区金沙江路 1518 弄",
  },
  {
    id: 2,
    date: "2016-05-04",
    name: "王小虎222",
    age: 22,
    address: "上海市普陀区金沙江路 1517 弄",
  },
  {
    id: 3,
    date: "2016-05-01",
    name: "王小虎333",
    age: 23,
    address: "上海市普陀区金沙江路 1519 弄",
  },
  {
    id: 4,
    date: "2016-05-03",
    name: "王小虎444",
    age: 24,
    address: "上海市普陀区金沙江路 1516 弄",
  },
  {
    id: 5,
    date: "2016-05-08",
    name: "王小虎555",
    age: 25,
    address: "上海市普陀区金沙江路 1518 弄",
  },
]);

onMounted(() => {
  rowDrop();
});

/**
 * 行拖拽排序
 */
function rowDrop() {
  // 要侦听拖拽响应的DOM对象
  const tbody = document.querySelector(".el-table__body-wrapper tbody");
  const data = tableData.value;
  Sortable.create(tbody, {
    // handle: ".el-icon-rank",
    ghostClass: "target-row-class",
    // 匹配的元素将不会触发拖动
    filter: ".filtered",
    // 拖拽移动事件,返回false取消移动
    onMove: function ({ related }) {
      return related.className.indexOf("filtered") === -1;
    },
    // 结束拖拽后的回调函数
    onEnd({ newIndex, oldIndex }) {
      // 将oldIndex位置的数据删除并取出,oldIndex后面位置的数据会依次前移一位
      const currentRow = data.splice(oldIndex, 1)[0];
      // 将被删除元素插入到新位置(currRow表示上面的被删除数据)
      data.splice(newIndex, 0, currentRow);
    },
  });
}

// 设置ID为1和5的行禁止拖拽
function tableRowClassName({ row, rowIndex }) {
  const freezeList = [1, 5];
  return freezeList.includes(row.id) ? "filtered" : "";
}
</script>

<template>
  <el-table
    ref="table"
    :data="tableData"
    style="width: 100%"
    border
    row-key="id"
    :row-class-name="tableRowClassName"
  >
    <el-table-column prop="date" label="日期" />
    <el-table-column prop="name" label="姓名" />
    <el-table-column prop="age" label="年龄" />
    <el-table-column prop="address" label="地址" />
    <!--<el-table-column align="center" width="55">-->
    <!--  <i class="el-icon-rank" />-->
    <!--</el-table-column>-->
  </el-table>
</template>

<style scoped lang="less">
.el-table {
  ::v-deep {
    .target-row-class {
      background: #f0f9eb;
    }
	// 禁止拖拽行背景色
    .filtered {
      background-color: #1db1e7 !important;
    }
  }
}
</style>

列拖拽

基本实现

效果

html 复制代码
<script setup>
import { onMounted, ref } from "vue";
import Sortable from "sortablejs";

const columns = ref([
  { label: "日期", prop: "date" },
  { label: "姓名", prop: "name" },
  { label: "年龄", prop: "age" },
  { label: "地址", prop: "address" },
]);

const tableData = ref([
  {
    id: 1,
    date: "2016-05-02",
    name: "王小虎111",
    age: 21,
    address: "上海市普陀区金沙江路 1518 弄",
  },
  {
    id: 2,
    date: "2016-05-04",
    name: "王小虎222",
    age: 22,
    address: "上海市普陀区金沙江路 1517 弄",
  },
  {
    id: 3,
    date: "2016-05-01",
    name: "王小虎333",
    age: 23,
    address: "上海市普陀区金沙江路 1519 弄",
  },
  {
    id: 4,
    date: "2016-05-03",
    name: "王小虎444",
    age: 24,
    address: "上海市普陀区金沙江路 1516 弄",
  },
  {
    id: 5,
    date: "2016-05-08",
    name: "王小虎555",
    age: 25,
    address: "上海市普陀区金沙江路 1518 弄",
  },
]);

onMounted(() => {
  columnDrop();
});

/**
 * 列拖拽排序
 */
function columnDrop() {
  // 要侦听拖拽响应的DOM对象
  const wrapperTr = document.querySelector(".el-table__header-wrapper tr");
  Sortable.create(wrapperTr, {
    animation: 180,
    delay: 0,
    onEnd({ newIndex, oldIndex }) {
      const draggedItem = columns.value.splice(oldIndex, 1)[0];
      columns.value.splice(newIndex, 0, draggedItem);
    },
  });
}
</script>

<template>
  <el-table
    ref="table"
    :data="tableData"
    style="width: 100%"
    border
    row-key="id"
  >
    <el-table-column
      v-for="(column, index) in columns"
      :key="index"
      :prop="column.prop"
      :label="column.label"
    />
  </el-table>
</template>

禁止某几行拖拽

效果

html 复制代码
<script setup>
import { onMounted, ref } from "vue";
import Sortable from "sortablejs";

const columns = ref([
  { label: "日期", prop: "date" },
  { label: "姓名", prop: "name", draggable: true },
  { label: "年龄", prop: "age", draggable: true },
  { label: "地址", prop: "address" },
]);

const columnsDrop = ref([
  { label: "日期", prop: "date" },
  { label: "姓名", prop: "name" },
  { label: "年龄", prop: "age" },
  { label: "地址", prop: "address" },
]);

const tableData = ref([
  {
    id: 1,
    date: "2016-05-02",
    name: "王小虎111",
    age: 21,
    address: "上海市普陀区金沙江路 1518 弄",
  },
  {
    id: 2,
    date: "2016-05-04",
    name: "王小虎222",
    age: 22,
    address: "上海市普陀区金沙江路 1517 弄",
  },
  {
    id: 3,
    date: "2016-05-01",
    name: "王小虎333",
    age: 23,
    address: "上海市普陀区金沙江路 1519 弄",
  },
  {
    id: 4,
    date: "2016-05-03",
    name: "王小虎444",
    age: 24,
    address: "上海市普陀区金沙江路 1516 弄",
  },
  {
    id: 5,
    date: "2016-05-08",
    name: "王小虎555",
    age: 25,
    address: "上海市普陀区金沙江路 1518 弄",
  },
]);

// 定义变量来记录固定列的class名
const fixedColumnClass = "filtered";

onMounted(() => {
  columnDrop();
});

function setHeaderCellClass({ column }) {
  const columnLabels = columns.value
    .filter((column) => column.draggable)
    .map((column) => column.label);
  return !columnLabels.includes(column.label) ? fixedColumnClass : "";
}

/**
 * 列拖拽排序
 */
function columnDrop() {
  // 要侦听拖拽响应的DOM对象
  const wrapperTr = document.querySelector(".el-table__header-wrapper tr");
  Sortable.create(wrapperTr, {
    animation: 180,
    delay: 0,
    ghostClass: "target-row-class",
    filter: `.${fixedColumnClass}`,
    // filter: (event, item) => {
    //   // 也可以根据item的类名、id或其他属性来决定是否应该被排除
    //   return !item.classList.contains("draggable");
    // },
    onMove: function ({ related }) {
      return related.className.indexOf(fixedColumnClass) === -1;
    },
    onEnd({ newIndex, oldIndex }) {
      const draggedItem = columnsDrop.value.splice(oldIndex, 1)[0];
      columnsDrop.value.splice(newIndex, 0, draggedItem);
    },
  });
}
</script>

<template>
  <el-table
    ref="table"
    :data="tableData"
    style="width: 100%"
    border
    row-key="id"
    :header-cell-class-name="setHeaderCellClass"
  >
    <el-table-column
      v-for="(column, index) in columns"
      :key="column.prop"
      :prop="columnsDrop[index].prop"
      :label="column.label"
    />
  </el-table>
</template>

<style scoped lang="less">
.el-table {
  ::v-deep {
    .target-row-class {
      background: #f0f9eb;
    }

    .filtered {
      background-color: #1db1e7 !important;
    }
  }
}
</style>

封装Vue指令

未完待续

相关推荐
a栋栋栋2 小时前
apifox
java·前端·javascript
_可乐无糖2 小时前
Fastbot-iOS(iOS monkey)schema参数的指定方式
ui·ios·自动化
Anlici3 小时前
React18与Vue3组件通信对比学习(详细!建议收藏!!🚀🚀)
前端·vue.js·react.js
m0_748251523 小时前
PDF在线预览实现:如何使用vue-pdf-embed实现前端PDF在线阅读
前端·vue.js·pdf
lauo5 小时前
【智体OS】官方上新发布“空钥登陆”--方便访客使用智体操作系统OS和智体应用
前端·javascript·分布式·机器人·开源
哥谭居民00015 小时前
普通的树形数据primevue的treetable组件的treetable[ ]
前端·javascript·算法
sorryhc5 小时前
基于H5请求劫持能力如何设计一款异常监听SDK?
前端·javascript·架构
粥里有勺糖5 小时前
视野修炼-技术周刊第115期 | 现代的 Nodejs 能力
前端·javascript·github
徐小黑ACG5 小时前
JavaScript 基础
开发语言·javascript
郑大乾6667 小时前
vuex - 第一天
javascript·vue.js·node.js