orgManager/src/components/TextDragSort/index.vue

147 lines
4.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="">
<div>
<el-icon class="sort-icon" color="#409eff" size="15">
<Rank />
</el-icon>
<el-link type="primary" :underline="false" :disabled="row.sortNo === 1"
@click="moveUp">{{ t('') }}</el-link>
<el-link type="primary" :underline="false" :disabled="row.sortNo === 1"
@click="moveDown">{{ t('') }}</el-link>
</div>
<div><el-link type="primary" :underline="false" :disabled="row.sortNo === 1"
@click="moveTop">{{ t('') }}</el-link></div>
</div>
</template>
<script setup>
import Sortablejs from 'sortablejs';
const props = defineProps({
id: {
type: String,
default: ''
},
row: {
type: Object,
default: () => ({})
},
tableList: {
type: Array,
default: () => []
}
});
const emits = defineEmits(['update:tableList', 'dragEnd'])
const initDrag = () => {
// 首先,使用 document.querySelector 方法选取页面上指定的元素。这里的选择器 '.el-table__body-wrapper table tbody' 定位到一个表格的 tbody 部分
let el = document.querySelector('.el-table__body-wrapper table tbody');
const tbody = document.querySelector('.el-table__body-wrapper table tbody')
// 同一个页面有多个表格需要排序的话,需要给每个表格添加一个唯一的 id然后在 Sortablejs.create 方法中传入该 id这样就可以保证每个表格的拖拽排序互不干扰
if (props.id) {
el = document.querySelector(`#${props.id} tbody`);
}
// 创建了一个 Sortable.js 实例,将 el 作为容器,用于拖拽排序
Sortablejs.create(tbody, {
animation: 150,
handle: '.sort-icon',
draggable: '.parent-row',
onStart(evt) {
const parentRow = evt.item; // 被拖动的父行
const children = [];
// 收集所有紧跟的子行
let next = parentRow.nextElementSibling;
while (next && !next.classList.contains('parent-row')) {
children.push(next);
next = next.nextElementSibling;
}
// 用一个 DocumentFragment 临时保存子行
const fragment = document.createDocumentFragment();
children.forEach(child => fragment.appendChild(child));
parentRow._movedChildren = fragment;
},
onEnd(evt) {
const parentRow = evt.item;
const movedChildren = parentRow._movedChildren;
if (movedChildren) {
// 插回子行
let insertAfter = parentRow.nextElementSibling;
while (insertAfter && !insertAfter.classList.contains('parent-row')) {
insertAfter = insertAfter.nextElementSibling;
}
while (movedChildren.firstChild) {
tbody.insertBefore(movedChildren.firstChild, insertAfter);
}
parentRow._movedChildren = null;
}
// === 关键修复:重新按父行计算索引 ===
const parentRowsDom = Array.from(tbody.querySelectorAll('.parent-row'));
const oldParentIndex = evt.oldIndex;
const newParentIndex = parentRowsDom.indexOf(parentRow); // 用真实DOM顺序算新索引
// 找父行在 props.tableList 里的真实索引
const parentRows = props.tableList
.map((row, idx) => ({ row, idx }))
.filter(item => item.row.merchName);
const oldIndex = parentRows[oldParentIndex].idx;
const newIndex = parentRows[newParentIndex].idx;
// === 移动父子数据一起 ===
// 找出被拖动父行和所有子行
let groupEnd = oldIndex + 1;
for (let i = oldIndex + 1; i < props.tableList.length; i++) {
if (props.tableList[i].merchName) break;
groupEnd++;
}
const movedGroup = props.tableList.splice(oldIndex, groupEnd - oldIndex);
// 插入到新位置
let insertIndex = newIndex;
if (newIndex > oldIndex) insertIndex = newIndex - (groupEnd - oldIndex) + 1;
props.tableList.splice(insertIndex, 0, ...movedGroup);
emits('dragEnd', { merchName: movedGroup[0].merchName, sort: insertIndex + 1 });
}
});
}
const moveUp = () => {
if (props.row.sort <= 1) return;
emits('dragEnd', { merchName: props.row.merchName, direction: 'up', sort: props.row.sort - 1 });
}
const moveDown = () => {
if (props.row.sort >= props.tableList.length) return;
emits('dragEnd', { merchName: props.row.merchName, direction: 'down', sort: props.row.sort + 1 });
}
const moveTop = () => {
if (props.row.sort <= 1) return;
emits('dragEnd', { merchName: props.row.merchName, sort: 1, isTop: true });
}
onMounted(() => {
nextTick(() => {
initDrag()
})
})
</script>
<style scoped lang="scss">
.sort {
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
}
.sort-icon {
cursor: pointer;
}
</style>