4.x版本的ant-table+sortablejs实现拖拽排序
实现效果图:
遇到的问题:
因为功能需求,我需要在排序完后,再对排序后的tableData进行排序检查,因为,被锁的字段只能排在最前面,如果排序后的tableData的不符合要求则会对其进行重排序,将被锁的字段放在对前面。
但是现在的问题是,因为我进行了排序检查和二次排序,导致数据tableData确实是正确的,但是组件table确实不正确的。想来是因为DOM没有刷新,造成的。
直观的问题是,我将某个字段排序放到最后一个的时候,这个字段即会在最后一个显示也会在第一个显示。
我想到的解决办法是对table组件增加个key每次排序完后改变key,让table强制刷新。但是这也出现了第二个问题,每次强制刷新完table后滚动条就会重置到最顶端。这给用户的体验非常不好。
解决这个问题的办法也很简单,那就是使用原生的js,给table这个盒子增加个滚动监听事件,记录每次滚动的距离,再排完序强制刷新后再让table滚动到上次记录的位置就可以了(邪修)。这个滚动是在页面显示前就完成了不会造成闪烁问题。
代码:
<script setup>
import { LockOutlined, MenuOutlined, UnlockOutlined } from '@ant-design/icons-vue'
import Sortable from 'sortablejs'
import { nextTick, onUnmounted, ref } from 'vue'const props = defineProps({rowSelection: {type: Object,default: () => null,},tableData: {type: Array,default: () => ref([]),},
})
const emit = defineEmits(['dragMove', 'lock'])
const columns = [{title: '锁定',dataIndex: 'lock',align: 'center',width: 80,},{title: '列名',dataIndex: 'title',align: 'left',ellipsis: true,width: 240,},{title: '排序',dataIndex: 'id',align: 'center',},
]
const table = ref(null)
const keyValue = ref(0)
const scrollTop = ref(0)function setScroll(y) {const scrollContainer = table.value?.$el?.querySelector('.kgd-table-body')scrollContainer.scrollTop = y
}
function handleTableScroll(e) {scrollTop.value = e.target.scrollTop
}
function watchScroll() {const scrollContainer = table.value?.$el?.querySelector('.kgd-table-body')if (scrollContainer) {scrollContainer.addEventListener('scroll', handleTableScroll)}
}
function initSortable() {const tableSort = table.valuewatchScroll()// 另外一种获取方法const array = tableSort.$el.querySelectorAll('tbody') // 所有tobodySortable.create(array[0], {handle: '.drag-id',animation: 150,draggable: '.kgd-table-row',onEnd: ({ newIndex, oldIndex }) => {tableSort.$forceUpdate()if (newIndex !== oldIndex) {emit('dragMove', newIndex - 1, oldIndex - 1)keyValue.value++nextTick(() => {initSortable()})}},})nextTick(() => {setScroll(scrollTop.value)})
}function lock(row) {emit('lock', row)
}defineExpose({initSortable,
})onUnmounted(() => {const scrollContainer = table.value?.$el?.querySelector('.kgd-table-body')if (scrollContainer) {scrollContainer.removeEventListener('scroll', handleTableScroll)}
})
</script><template><a-tableref="table":key="keyValue"size="middle":row-selection="props.rowSelection":data-source="props.tableData":columns="columns":pagination="false"row-key="dataIndex":scroll="{ y: 'calc(100vh - 350px)' }"><template #bodyCell="{ column, record }"><template v-if="column.dataIndex === 'id'"><MenuOutlined v-if="record.fixed !== 'right'" class="drag-id" /></template><template v-if="column.dataIndex === 'lock'"><a v-if="record.fixed !== 'right'" class="btn_lock" @click="() => { lock(record) }"><LockOutlined v-if="record.fixed === 'left'" /><UnlockOutlined v-else style="color: #8e8e8e;" /></a></template></template></a-table>
</template><style scoped lang="less">
.drag-id {cursor: move;color: #00a578;
}
</style>