Element-UI ,Table组件实现拖拽效果

最近业务需求要添加table的拖拽,但是element并没有table的拖拽功能,只能自己添加了。

找了两个组价库sortablejsvuedraggable,后者是基于前者实现的更加符合vue标准的库,依赖于前者,但是项目中用的element的table, vuedraggable在这个基础上就不能使用,看官方的示例 (opens new window) , 所以只能使用sortablejs了,我直接安装了vuedraggable,它依赖sortablejs可以直接使用里面的特性,万一后期再有其他拖拽的功能,这个库上手还比较方便。

# Sortable使用示例

<template>
    <el-card v-loading="fullscreenLoading">
        <el-table
                :data="tableOptions.data"
                border
                size="small"
                row-key='roleId'
                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.prop"
                    :prop="item.prop"
                    :label="item.label"
                    :width="item.width"
                    :fixed="item.fixed"
            />
        </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"
        />
    </el-card>
</template>
<script>
  import Sortable from 'sortablejs';
  import table from "@/mixins/table"

  export default {
    name: 'TableDraggable',
    mixins: [table],
    props: {},
    data() {
      return {
        column: [
          {
            prop: "roleId",
            label: "序号",
            width: 100,
          },
          {
            prop: 'roleName',
            label: "角色名称",
          },
          {
            prop: "createTime",
            label: "创建时间",
          },
          {
            prop: "roleId",
            label: "序号",
            width: 100,
          },
          {
            prop: 'edit',
            label: "编辑",
            width: 180,
            fixed: 'right'
          },
        ],
        fullscreenLoading: true,
        paginationOptions: {
          pageSizes: [10, 20, 30, 40],
        },
      }
    },
    watch: {
      'tableOptions.data': {
        deep: true,
        handler: function (newData) {
          // console.log(newData);  // 可以发现每次拖拽后数据发生了改变
        }
      }
    },
    methods: {
      //行拖拽
      rowDrop() {
        const tbody = this.$refs.table.$el.querySelector('.el-table__body-wrapper tbody');
        const _this = this;
        Sortable.create(tbody, {
          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)
          }
        })
      }
    }
  }
</script>

<style type="text/scss" lang="scss" scoped>
    .handle {
        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>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

上面的代码有一些注意的地方我一一列举下来

  1. element table务必指定row-key,row-key必须是唯一的,不然会出现排序不对的情况。
  2. 我在table里面使用了fixed,最后一列是固定在右侧,用过element的知道这是两个table的拼接成的,所以拖拽是没有反应的
    1. 以因为上面我们有指定row-key,所以拖拽后不会出现错位的情况,但是在拖拽的时候,是有很明显的错位出现。
    2. 我解决的思路是在拖拽的时候先把这个固定取消onChoose,然后拖拽完成后在把固定加上onUnchoose,具体看两个方法的代码
  3. 样式table会有鼠标滑过的效果,但是使用拖拽后,鼠标滑过后的效果不消失,甚至会出现很多个鼠标滑过的效果,解决的方式比较粗暴,我是把所有的滑过的效果全部取消了,谁有更好的方案欢迎评论区留言。
    1. 不使用fixed,可以防止2、3问题
  4. mounted生命周期调取的rowDrop方法,会出现的问题是,如果在created调取的接口量大在mounted周期可能不能更好的渲染完成,此时将获取不到tbody,所以这里我的解决办法就是使用,table组件自带的@cell-mouse-enter.once='rowDrop',hover滑过的时候完成初始化,加上once是他只需要执行一次,或者更粗暴的办法直接使用定时器。

# 参考文档

draggable (opens new window)

sortable (opens new window)