最近业务需求要添加table的拖拽,但是element并没有table的拖拽功能,只能自己添加了。
找了两个组价库sortablejs
和vuedraggable
,后者是基于前者实现的更加符合vue标准的库,依赖于前者,但是项目中用的element的table, vuedraggable
在这个基础上就不能使用,看官方的示例 , 所以只能使用sortablejs
了,我直接安装了vuedraggable
,它依赖sortablejs
可以直接使用里面的特性,万一后期再有其他拖拽的功能,这个库上手还比较方便。
Sortable使用示例
<template>
<div>
<el-table
:data="tableOptions.data"
border
size="small"
row-key='id'
ref="table"
@cell-mouse-enter.once='rowDrop'
>
<el-table-column
prop="sort"
label="拖拽区域"
>
<template slot-scope="scope">
<el-button type="text" size="small" class="handle">按住拖拽</el-button>
</template>
</el-table-column>
<el-table-column
v-for="item of column"
:key="item.id"
:prop="item.prop"
:label="item.label"
:width="item.width"
:fixed="item.fixed"
:class-name="item['class-name']" // 这个是列拖拽使用
/>
</el-table>
<el-pagination
background
:hide-on-single-page="paginationOptions.showPage"
:layout="paginationOptions.layout"
:page-sizes="paginationOptions.pageSizes"
:total="paginationOptions.total"
:page-size="paginationOptions.pageSize"
:current-page="paginationOptions.currentPage"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import Sortable from 'sortablejs';
import table from '@/mixins/table';
export default {
mixins: [table],
props: {},
data() {
return {
column: [
{
prop: 'id',
label: '序号',
width: 100,
},
{
prop: 'roleName',
label: '角色名称',
'class-name': 'canDrag',
},
{
prop: 'createTime',
label: '创建时间',
'class-name': 'canDrag',
},
{
prop: 'roleId',
label: '角色Id',
width: 100,
},
{
prop: 'edit',
label: '编辑',
width: 180,
fixed: 'right',
},
],
paginationOptions: {
pageSizes: [10, 20, 30, 40],
},
};
},
watch: {
'tableOptions.data': {
deep: true,
handler: function(newData) {
// console.log(newData); // 可以发现每次拖拽后数据发生了改变
},
},
},
mounted() {
this.tableOptions.data = [
{ id: '1', roleName: 'test1', createTime: '202011115', roleId: 10 },
{ id: '2', roleName: 'test2', createTime: '202011116', roleId: 21 },
{ id: '3', roleName: 'test3', createTime: '202011117', roleId: 22 },
{ id: '4', roleName: 'test4', createTime: '202011118', roleId: 25 },
];
},
methods: {
rowDrop() {
// 行拖拽
const _this = this;
const tbody2 = this.$refs.table.$el.querySelector('.el-table__body-wrapper tbody');
Sortable.create(tbody2, {
handle: '.handle',
animation: 150,
onChoose() {
//选择元素
_this.column[_this.column.length - 1].fixed = false;
},
onUnchoose: function(evt) {
// 取消选择元素
_this.column[_this.column.length - 1].fixed = 'right';
},
onEnd({ newIndex, oldIndex }) {
// 拖拽完成
const currRow = _this.tableOptions.data.splice(oldIndex, 1)[0];
_this.tableOptions.data.splice(newIndex, 0, currRow);
},
});
// // 列拖拽
// const tbody = this.$refs.table.$el.querySelector('.el-table__header-wrapper tr');
// Sortable.create(tbody, {
// draggable: '.canDrag',
// animation: 150,
// onEnd({ newIndex, oldIndex }) {
// // 拖拽完成
// const currRow = _this.column.splice(oldIndex - 1, 1)[0];
// _this.column.splice(newIndex - 1, 0, currRow);
// },
// });
},
},
};
</script>
<style type="text/scss" lang="scss">
.handle, .canDrag {
cursor: move
}
::v-deep .hover-row > td {
background-color: #fff !important;
}
::v-deep .sortable-chosen > td {
// 拖动的样式
background-color: #eff2f6 !important;
}
::v-deep .el-table--enable-row-hover .el-table__body tr:hover > td {
// 修复拖拽的时候hover的不消失的问题
background-color: #fff;
}
</style>
上面的代码有一些注意的地方我一一列举下来
- element table务必指定
row-key
,row-key必须是唯一的,不然会出现排序不对的情况。 - 我在table里面使用了fixed,最后一列是固定在右侧,用过element的知道这是两个table的拼接成的,所以拖拽是没有反应的
- 因为上面我们有指定row-key,所以拖拽后不会出现错位的情况,但是在拖拽的时候,是有很明显的错位出现。
- 我解决的思路是在拖拽的时候先把这个固定取消
onChoose
,然后拖拽完成后在把固定加上onUnchoose
,具体看两个方法的代码
- 样式table会有鼠标滑过的效果,但是使用拖拽后,鼠标滑过后的效果不消失,甚至会出现很多个鼠标滑过的效果,解决的方式比较粗暴,我是把所有的滑过的效果全部取消了,谁有更好的方案欢迎评论区留言。
- 不使用
fixed
,可以防止2、3 问题
- 不使用
mounted
生命周期调取的rowDrop
方法,会出现的问题是,如果在created
调取的接口量大在mounted
周期可能不能更好的渲染完成,此时将获取不到tbody
,所以这里我的解决办法就是使用,table组件自带的@cell-mouse-enter.once='rowDrop'
,hover滑过的时候完成初始化,加上once是他只需要执行一次,或者更粗暴的办法直接使用定时器。