el-table 的拖拽使用 Sortable.js
官方文档 :https://github.com/SortableJS/Sortable
1. 通过 npm 使用 sortable
//安装sortablejs
npm install sortablejs --save
//引用 sorttablejs
import Sortable from 'sortablejs'
2.用法
SorRow() {
// 获取表格row的父节点
const tbody = this.$refs.table.$el.querySelector( ".el-table__body-wrapper tbody");
// 创建行拖拽实例
const dragTableRow = Sortable.create(tbody, {
animation: 150, //动画
handle: ".move", //指定拖拽目标,点击此目标才可拖拽元素(此例中设置操作按钮拖拽)
filter: ".disabled", //指定不可拖动的类名(el-table中可通过row-class-name设置行的class)
dragClass: "dragClass", //设置拖拽样式类名
ghostClass: "ghostClass", //设置拖拽停靠样式类名
chosenClass: "chosenClass", //设置选中样式类名
// 开始拖动事件
onStart: () => {
console.log("开始拖动");
},
// 结束拖动事件
onEnd: (e) => {
console.log(
"结束拖动",
`拖动前索引${e.oldIndex}---拖动后索引${e.newIndex}`
);
},
});
},
// 列拖拽
SorCol() {
//获取表格col的父节点
const eleCol = this.$refs.table.$el.querySelector(".el-table__header-wrapper tr");
// 创建列拖拽实例
const dragTableCol = Sortable.create(eleCol, {
animation: 150,
dragClass: "dragClass",
ghostClass: "ghostClass",
chosenClass: "chosenClass",
// 结束拖动事件
onEnd: (e) => {
// 拖拽结束之后通过修改tableHeaderData顺序改变表头顺序
const dragHeaderCopy = this.tableHeaderData[e.oldIndex]; // 备份当前拖拽的表头
this.tableHeaderData.splice(e.oldIndex, 1); //把当前拖动的表头去掉
this.tableHeaderData.splice(e.newIndex, 0, dragHeaderCopy); //把当前拖拽的表头添加到新位置
/**
* 在做列拖拽功能时发现问题:表头位置错乱,但是内容列正常
* 于是我给el-table绑定key,每次拖拽结束改变key触发表格重新渲染。
* 但引出新的问题:表格重渲拖拽事件丢失,导致之后无法拖拽
* 于是我在表格重渲之后重新调用拖拽方法创建拖拽实例,功能正常
* **/
this.key += 1;
this.$nextTick(() => {
this.SorRow();
this.SorCol();
});
console.log(dragHeaderCopy, "结束拖动", this.tableHeaderData);
},
});
},
// 设置表格row的class(此例中通过设置class来配合拖拽属性filter设置某行不可拖拽)
tableRowClassName({ row }) {
if (row.disabled) {
return "disabled";
}
return "";
},
<style lang='scss'>
// 拖拽
.dragClass {
background: rgba($color: #41c21a, $alpha: 0.5) !important;
}
// 停靠
.ghostClass {
background: rgba($color: #6cacf5, $alpha: 0.5) !important;
}
// 选择
.chosenClass:hover > td {
background: rgba($color: #f56c6c, $alpha: 0.5) !important;
}
</style>
3.实际使用
<template>
<div class="container">
<el-table
:data="tableData"
ref="table"
row-key="roleId"
@cell-mouse-enter.once="eventDrag"
border
size="small"
>
<el-table-column prop="sort" label="拖拽区域">
<template>
<el-button type="text" size="small" class="handle"
>按住拖拽</el-button
>
</template>
</el-table-column>
<el-table-column width="60px" label="序号" type="index"></el-table-column>
<!-- 此处如果只有行拖动,可以全部替换为 item -->
<el-table-column
v-for="(item, index) of dropCol"
:key="`dropCol_${index}`"
:prop="dropColumn[index].prop"
:label="item.label"
:width="item.width"
:fixed="item.fixed"
/>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button size="small">{{ scope.row.edit }}</el-button>
<el-button size="small">{{ scope.row.del }}</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Sortable from "sortablejs";
export default {
name: "HelloWorld",
props: {
msg: String,
},
data() {
return {
tableData: [
{
roleId: 20001,
roleName: "咯阿时候1",
createTime: "2021-06",
edit: "编辑",
del: "删除",
},
{
roleId: 20002,
roleName: "咯阿时候2",
createTime: "2021-07",
edit: "编辑",
del: "删除",
},
{
roleId: 20003,
roleName: "咯阿时候3",
createTime: "2021-08",
edit: "编辑",
del: "删除",
},
],
dropColumn: [
{ prop: "roleId", label: "编码", width: 100 },
{ prop: "roleName", label: "角色名称" },
{ prop: "createTime", label: "创建时间" },
{ prop: "edit", label: "编辑", width: 180, fixed: "right" },
],
dropCol: [
{ prop: "roleId", label: "编码", width: 100 },
{ prop: "roleName", label: "角色名称" },
{ prop: "createTime", label: "创建时间" },
{ prop: "edit", label: "编辑", width: 180, fixed: "right" },
],
};
},
watch: {
"tableOptions.data": {
deep: true,
handler: function (newData) {
console.log(newData); // 可以发现每次拖拽后数据发生了改变
},
},
},
methods: {
eventDrag() {
this.rowDrop();
this.columnDrop();
},
mounted() {},
//行拖拽
rowDrop() {
//此处需要使用this.$refs.table.$el.querySelector,不然可能获取不到 tbody
const tbody = this.$refs.table.$el.querySelector(
".el-table__body-wrapper tbody"
);
console.log(tbody);
const _this = this;
Sortable.create(tbody, {
handle: ".handle", //此处指定拖拽元素
animation: 150,
onChoose() {
//选择元素
_this.dropColumn[_this.dropColumn.length - 1].fixed = false;
},
onUnchoose: function (evt) {
// 取消选择元素
_this.dropColumn[_this.dropColumn.length - 1].fixed = "right";
},
onEnd({ newIndex, oldIndex }) {
// 拖拽完成
const currRow = _this.tableData.splice(oldIndex, 1)[0];
_this.tableData.splice(newIndex, 0, currRow);
},
});
},
//列拖拽
columnDrop() {
const wrapperTr = this.$refs.table.$el.querySelector(
".el-table__header-wrapper tr"
);
console.log(wrapperTr);
this.sortable = Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: (evt) => {
const arr = JSON.parse(JSON.stringify(this.dropCol));
const oldItem = arr[evt.oldIndex];
arr.splice(evt.oldIndex, 1);
arr.splice(evt.newIndex, 0, oldItem);
this.$nextTick(() => {
this.dropCol = arr;
});
},
});
},
},
};
</script>
4.在线链接
https://codesandbox.io/embed/gifted-hill-sdozr?fontsize=14&hidenavigation=1&theme=dark