vue元素拖拽与序号编写协同修改排序

这是我参与更文挑战的第16天,活动详情查看: 更文挑战

因运营人员需要排序某个产品列表,这里记录使用SortableJS实现元素排序的过程。

sortableJs官网

引入

package.json中添加:

1
"sortablejs": "1.8.4",

需要排序的组件上添加:

1
import Sortable from 'sortablejs'

添加控制标签

在需要添加拖拽效果的控件上添加id标签。vue环境下为el-table增加拖拽排序则需要添加refrow-key,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
<el-table
ref="myDragTable"
v-loading="loading"
:data="dataList"
row-key="id"
element-loading-text="商品加载中"
border
fit
style="width: 100%;"
highlight-current-row
>
....
</el-table>

其中的关键在于以下两个标签:

1
2
ref="myDragTable"
row-key="id"

不要忘记设置row-key,否则会发生拖拽后行不规则的移动。

给其中的某列添加拖拽功能标识:

1
2
3
4
5
<el-table-column align="center" label="拖动" width="45" class-name="allow">
<template>
<i class="el-icon-rank" />
</template>
</el-table-column>

该列展示效果如下图所示:

image.png

辅助数据与排序方法

在vue组件的data中需要添加两个数组来记录拖拽前与拖拽后的顺序:

1
2
3
4
5
6
7
data() {
return {
dataList: [...] // 列表展示数据
oldPList: [], // 排序用
newPList: [] // 排序用
}
}

两个排序数组的初始化应该放在什么地方呢?

setSort方法又该在什么时间点去执行呢?

应该在获取数据之后与渲染DOM之后,关键代码如下图:

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
methods: {
getData() {
api...({ // 请求后端数据
...
}).then(res => {
// 这里表示已从后端获取了数据
this.dataList = res.data
this.oldPList = this.dataList.map(v => v.id)
this.newPList = this.oldPList.slice()
this.$nextTick(() => {
// 表示在渲染dom之后调用setSort方法
this.setSort()
})
})
},
setSort() {
// 获取操作元素
const el = this.$refs.myDragTable.$el.querySelectorAll('.el-table__body-wrapper > table > tbody')[0]
this.sortable = Sortable.create(el, {
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
handle: '.allow', // 仅某一列可以拖动,这样不影响其他列的点击,复制功能
setData: function(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
},
onEnd: evt => {
/*这里就是在处理拖拽后的重新排序了*/
// 找到所拖拽的行
const targetRow = this.dataList.splice(evt.oldIndex, 1)[0]
// 操作原数据,重新排列所拖拽行的位置
this.dataList.splice(evt.newIndex, 0, targetRow)

// 以下步骤为通过重新排序,将新的排序通过接口告知后端,后端数据重排
const tempIndex = this.newPList.splice(evt.oldIndex, 1)[0]
this.newPList.splice(evt.newIndex, 0, tempIndex)
// 调用接口更新排序
// updateOrder({ tabsOrder: this.newPList }).then(response => {
// this.$message.success('更新排序成功')
// })
}
})
},
}

具体接口配置信息:http://www.sortablejs.com/options.html

编写序号排序

拖拽排序适合少量数据的情况,不适合大数据量或者将一个元素从末尾拖到头部。我们还需要可以手动修改序号的方式来辅助。

image.png

这样操作人员可以很方便的将某些元素置顶或设置到末尾。

我们需要监听el-inputchange事件,请求后台,更新排序信息。

为什么是监听change事件而不是input事件呢?因为input事件在你的输入框内有任何变动时会立即请求,而change则会在你输入完毕后(比如输入完毕点击enter或者鼠标点击空白处等)