在前端开发中,遇到一个页面是由一个Tabs 标签页组成,每个标签页下面有多个数量不定的表格(可以通过页面提供的按钮来增删表格)。每个表格都要实现自己内的每行数据可拖动的功能。
这里用来实现拖动的工具是 sortablejs, 前端组件为element ui
数据结构大致为:
data = {
'0': [
{
'table': []
},
{
'table': []
}
],
'1': [
{
'table': []
},
...
],
...
}
难点在于两个点:
1是由于表格数量是不确定的,如果找到每个表格来激活拖动功能
2是因为在拖动结束后需要对数据进行操作,所以在拖动的时候,如何确定拖动的是哪个表格
解决方案:
1. 对每一个标签页下面的每个表格绑定不同的动态class(<div :class="`draggable_0_${index_2}`">),这样就保证了每个表格都有一个唯一的draggable class:
<el-tabs v-model="activeName" type="card">
<el-tab-pane label="标签页1" name="0">
<div v-for="(item, index) in data.[activeName]" :key="item_2.idx">
<div :class="`draggable_0_${index}`">
<el-table :data="item.table" row-key="idx">
......
</el-table>
</div>
</div>
</el-tab-pane>
</el-tabs>
2. 需要一个收集所有 draggable class的函数,在初始化页面、增加表格、删除表格时调用。大致如下:
tab_list: [
{'label': '标签页1', 'name': '0'}, {'label': '标签页2', 'name': '1'},
{'label': '标签页3', 'name': '2'}, {'label': '标签页4', 'name': '3'}
],
draggable_class_list: [],
collectDragClass() {
this.draggable_class_list = []
for (let node of this.tab_list) {
let name = node['name']
for (let i=0; i<this.data.[name].length; i++) {
let cur_class = `draggable_${name}_${i}`;
if (!this.draggable_class_list.includes(cur_class)) {
this.draggable_class_list.push(cur_class)
}
}
};
}
3. 现在已经能定位每一个表格,其唯一的class也能帮助我们确定是要拖动哪个表格,所以最后要利用sortablejs增加拖动功能:
dragRow() {
let tbodys = []
// 定位每个表格
for (let node of this.draggable_class_list) {
let tb = document.querySelector(`.${node} .el-table__body-wrapper tbody`);
tbodys.push(tb)
}
let _this = this;
for (let i=0; i<tbodys.length; i++) {
let tbody = tbodys[i];
let cur_class = this.draggable_class_list[i];
let class_split = cur_class.split('_')
let tab_name = class_split[1];
let index = Number(class_split[2]);
Sortable.create(tbody, {
draggable: ".el-table__row",
onEnd: evt => {
// 利用表格class的唯一性信息来确定拖动的是哪个表格内容
let target_data = _this.data.[tab_name][index].table
const targetRow = target_data.splice(evt.oldIndex, 1)[0];
target_data.splice(evt.newIndex, 0, targetRow);
}
})
}
},
4. 每次表格数量变化的时候,都执行收集表格class并激活拖动功能即可:
this.collectDragClass()
let _this = this;
setTimeout(() => {
_this.dragRow()
}, 1000);