sortablejs插件在el-table中的运用
概述需求
有一个Table表格,由于数据是根据自增的ID进行排序显示的,有时了调整顺序会在数据库中直接操作数据表,来达到调整数据顺序的目的,因为为了实现在页面实现较为简单的拖拽排序,因此展开讨论。 最后
sortablejs
插件可以满足需求并可以快捷的实现功能。
参看资料:
官网:http://www.sortablejs.com/
中文文档:https://www.itxst.com/sortablejs/neuinffi.html
1、安装sortablejs插件
首先引入依赖,并重启项目
代码语言:javascript复制npm install sortablejs --save
2、实现效果
首先看下实现的效果如下: 1、这是原来的顺序:[1, 2, 3, 4]
2、通过鼠标拖拉即可改变位置: [4, 3, 1, 2]
3、编写vue页面(文末有完整页面)
3.1、在需要编写排序的页面引入sortablejs依赖
代码语言:javascript复制import Sortable from 'sortablejs';
3.2、编写el-table并定义ref=“tableRef” ,ref可以理解为id
代码语言:javascript复制<template>
<div class="index">
<el-row>
<el-col>
<el-table :data="tableData" ref="tableRef"
size="small" border stripe>
<el-table-column align="center" label="模板ID" prop="id"></el-table-column>
<el-table-column align="center" label="模板信息" prop="mc"></el-table-column>
</el-table>
</el-col>
</el-row>
<el-row style="margin-top: 20px">
<el-col :offset="17" :span="6">
<el-button-group>
<el-button size="small" type="primary" @click="save">保存</el-button>
</el-button-group>
</el-col>
</el-row>
</div>
</template>
3.3、初始化页面
代码语言:javascript复制tableData: 页面初始化数据 newIndexList:复制初始化table的id,后续顺序调整将会直接对其操作。
export default {
name: "index",
components: {
Sortable
},
data() {
return {
// 表单数据
tableData: [
{
id: 1,
mc: "模板一"
},{
id: 2,
mc: "模板二"
},{
id: 3,
mc: "模板三"
},{
id: 4,
mc: "模板四"
}],
// 排序后的数据列表
newIndexList: [],
}
},
mounted() {
// 复制原Table的id按循序存储newIndexList中,
// 每一次调整位置会对newIndexList进行位置调整。
this.tableData.forEach( item => {
this.newIndexList.push(item.id);
});
//阻止火狐拖拽新建新页面
document.body.addEventListener("drop", (event) => {
event.preventDefault();
event.stopPropagation();
}, false);
this.initSortableList();
},
methods: {
// 更新排序
initSortableList(){
let el = this.$refs.tableRef.$el.querySelector('.el-table__body-wrapper tbody');
//设置配置
let _this = this
Sortable .create(el, {
animation: 150,
sort: true,
draggable: '.el-table__row', // 设置可拖拽行的类名(el-table自带的类名)
forceFallback: true,
onEnd({newIndex, oldIndex}) {
let currRow = _this.newIndexList.splice(oldIndex, 1)[0];
_this.newIndexList.splice(newIndex, 0, currRow);
}
})
},
}
}
3.4、核心部分编写排序规则
每一次鼠标拖拽Table的某一行进行排序都会执行onEnd()
方法。
newIndex:行数据移动到的新位置,起始角标为0。 oldIndex: 行数据原始的位置。
举个例子:将第四行移动到第一行,执行的顺序如下:
1、首先根据取得oldIndex=3
,取得第四列的id
2、将第四列的Id插入newIndex=0
的位置,而后其余的数据一次后排。
3、id的变化流程为 [1, 2, 3, 4] -> [4, 1, 2, 3]
// 更新排序
initSortableList(){
let el = this.$refs.tableRef.$el.querySelector('.el-table__body-wrapper tbody');
//设置配置
let _this = this
Sortable .create(el, {
animation: 150,
sort: true,
draggable: '.el-table__row', // 设置可拖拽行的类名(el-table自带的类名)
forceFallback: true,
onEnd({newIndex, oldIndex}) {
let currRow = _this.newIndexList.splice(oldIndex, 1)[0];
_this.newIndexList.splice(newIndex, 0, currRow);
}
})
},
3.5、保存设置参数
执行保存操作时,我们需要将排序没有改变的行数据去除掉。以上截图为例; 显然此次排序每一行的顺序都发生了变化,所以需要修改。
tableData.id newIndexList 1 4 2 3 3 1 4 2
基于上面数据分布格式,我们可以明白,以newIndexList为条件修改成tableData.id的值。
代码语言:javascript复制[
{
"key": 4,
"value": 1
},{
"key": 3,
"value": 2
},{
"key": 1,
"value": 3
},{
"key": 2,
"value": 4
}
]
如果字段id都是匹配,则说明没有进行位置调整,则不需要提交。
代码语言:javascript复制 //保存编辑完顺序后的数组
save(){
//1、封装需要更新的id <key, value> key: 原来id, value:新的id
// 等位对比,查看templateList和newIndexList每一项ID是否对应。
let sortList = [];
this.tableData.forEach( (item, index) => {
if(item.id !== this.newIndexList[index]){
sortList.push({
key: this.newIndexList[index],
value: item.id 10000
});
}
});
//2、如果循序没有改变,则执行退出
if(!sortList.length){
return;
}
//3、tableData数据顺序发生变化,则提交到数据库。
},
也许你会发现item.id 10000
这个有意思的地方,因为我们在更新排序时,修改的是主键,所以会存在主键冲突,所以先增加10000
,修改完成后根据已经修改的id在执行自减10000
操作,这样就可以实现主键ID的交换了。
vue代码如下:
代码语言:javascript复制 <template>
<div class="index">
<el-row>
<el-col>
<el-table :data="tableData" ref="tableRef"
size="small" border stripe>
<el-table-column align="center" label="模板ID" prop="id"></el-table-column>
<el-table-column align="center" label="模板信息" prop="mc"></el-table-column>
</el-table>
</el-col>
</el-row>
<el-row style="margin-top: 20px">
<el-col :offset="17" :span="6">
<el-button-group>
<el-button size="small" type="primary" @click="save">保存</el-button>
</el-button-group>
</el-col>
</el-row>
</div>
</template>
<script>
import Sortable from 'sortablejs';
export default {
name: "index",
components: {
Sortable
},
data() {
return {
// 表单数据
tableData: [
{
id: 1,
mc: "模板一"
},{
id: 2,
mc: "模板二"
},{
id: 3,
mc: "模板三"
},{
id: 4,
mc: "模板四"
}],
// 排序后的数据列表
newIndexList: [],
}
},
mounted() {
// 复制原Table的id按循序存储newIndexList中,
// 每一次调整位置会对newIndexList进行位置调整。
this.tableData.forEach( item => {
this.newIndexList.push(item.id);
});
//阻止火狐拖拽新建新页面
document.body.addEventListener("drop", (event) => {
event.preventDefault();
event.stopPropagation();
}, false);
this.initSortableList();
},
methods: {
// 更新排序
initSortableList(){
let el = this.$refs.tableRef.$el.querySelector('.el-table__body-wrapper tbody');
//设置配置
let _this = this
Sortable .create(el, {
animation: 150,
sort: true,
draggable: '.el-table__row', // 设置可拖拽行的类名(el-table自带的类名)
forceFallback: true,
onEnd({newIndex, oldIndex}) {
let currRow = _this.newIndexList.splice(oldIndex, 1)[0];
_this.newIndexList.splice(newIndex, 0, currRow);
}
})
},
//保存编辑完顺序后的数组
save(){
//1、封装需要更新的id <key, value> key: 原来id, value:新的id
// 等位对比,查看templateList和newIndexList每一项ID是否对应。
let sortList = [];
this.tableData.forEach( (item, index) => {
if(item.id !== this.newIndexList[index]){
sortList.push({
key: this.newIndexList[index],
value: item.id 10000
});
}
});
//2、如果循序没有改变,则执行退出
if(!sortList.length){
return;
}
//3、tableData数据顺序发生变化,则提交到数据库。
},
},
}
</script>
<style scoped>
</style>
4、如何保存数据库呢
4.1、假设数据表结构如下:
代码语言:javascript复制CREATE TABLE demo (
id BIGINT PRIMARY KEY auto_increment COMMENT '模板id序',
mc VARCHAR ( 100 ) COMMENT '模板名称'
);
4.2、使用MyBatis实现数据表ID的更新
使用的MyBatis
框架,通过动态SQL实现功能。
这里需要分两步走:
第一步
:将排序后的id 加上 10000并修改原来的 id。注意:这个10000的一定是你的表数据自增无法达到的数据才可以,否则会出现主键冲突(vue前端已经实现自增了,这里无需任何操作)。
UPDATE DEMO
SET ID =
<foreach collection="list" item="item" open="(CASE" close="END)">
WHEN ID = #{item.key} THEN #{item.value}
</foreach>
WHERE ID IN
<foreach collection="list" item="item" open="(" close=")" separator=",">
#{item.key}
</foreach>
第二步
:将修改的ID主键数值减10000
UPDATE DEMO
SET ID =
<foreach collection="list" item="item" open="(CASE" close="END)">
WHEN ID = #{item.value} THEN #{item.value} - 10000
</foreach>
WHERE ID IN
<foreach collection="list" item="item" open="(" close=")" separator=",">
#{item.value}
</foreach>
这样便捷的排序就实现了。