项目中使用 ElementUI 的 el-table 生成的表格,需要使用 Sortable.js 实现拖拽排序的功能,正常的拖拽没问题,但是拖拽后的数组顺序与 el-table 渲染的数据不一致,具体错误如下图所示:

查找原因发现,应该是未指定 el-table 行数据的 Key,导致 Table 渲染错误,遂添加 row-key="index" ,然而问题还是没有解决。

因为该组件通过 value 实现双向绑定,数据是通过 v-model 传递过来的,考虑数组数据按地址传值,遂使用 slice() 拷贝了新的数据,最终解决问题。

总结:
1、配置 row-key 唯一,避免 el-table 渲染数据错误;
2、拷贝数组数据,避免引用传值及双向绑定更新数据导致的错误。
<template>
<div class="table-setting-view-container">
<div class="settings">
<el-select v-model="defaultSort.key" placeholder="请选择" size="mini">
<el-option
v-for="item in items"
:key="item.key"
:label="item.label"
:value="item.key">
</el-option>
</el-select>
<el-checkbox v-model="defaultSort.desc">降序</el-checkbox>
<el-button type="primary" size="mini" @click="submit()">提交</el-button>
</div>
<el-table
ref="settingTable"
:data="items"
row-key="index"
border
max-height="520"
>
<el-table-column label="序号" align="center" type="index" width="50" />
<el-table-column label="显示项目" prop="label">
</el-table-column>
<el-table-column
label="显示"
width="50"
align="center">
<template slot-scope="scope">
<el-checkbox v-model="scope.row.show" />
</template>
</el-table-column>
<el-table-column
prop="width"
label="宽度"
width="60">
<template slot-scope="scope">
<el-input v-model="scope.row.width" size="mini"></el-input>
</template>
</el-table-column>
<el-table-column
label="排序"
width="50"
align="center">
<template slot-scope="scope">
<el-checkbox v-model="scope.row.sort"/>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script type="text/javascript">
import Sortable from 'sortablejs'
export default {
props: {
value: {
type: Array,
default: () => []
}
},
data() {
return {
user: {},
items: [],
defaultSort: {key: null, desc: 0}
};
},
watch: {
value: {
handler(newVal) {
this.items = newVal.slice();
},
immediate: true,
deep: true
}
},
created() {
this.$nextTick(() => {
this.setSortable()
})
},
methods: {
// 拖拽排序
setSortable() {
const el = this.$refs.settingTable.$el.querySelectorAll('.el-table__body-wrapper > table > tbody')[0]
this.sortable = Sortable.create(el, {
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
setData: function(dataTransfer) {
dataTransfer.setData('Text', '')
},
onEnd: evt => {
const targetRow = this.items.splice(evt.oldIndex, 1)[0]
this.items.splice(evt.newIndex, 0, targetRow);
this.items.forEach(ele => {
console.log(ele.index, ele.label)
});
console.log('==================')
}
})
},
// 提交
submit() {
this.items =this.items.map((item, index) => {
item.index = index + 1;
return item;
});
}
}
};
</script>
<style lang="scss" scoped>
.table-setting-view-container {
.settings {
margin-bottom: 10px;
.el-checkbox {
margin-left: 20px;
}
.el-button {
float: right;
}
}
::v-deep .el-table {
.el-table__cell {
padding: 5px 0;
}
.el-input {
.el-input__inner {
height: 24px;
line-height: 24px;
padding: 0 7px;
text-align: right;
}
}
.el-select {
width: 100%;
.el-input__inner {
text-align: center;
}
}
}
}
</style>
<style lang="scss">
.table-view-select-popper {
.el-select-dropdown__item {
height: 28px;
line-height: 28px;
padding: 0 7px;
text-align: center;
}
}
</style>











