forked from Tencent/tdesign-vue
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseDragSort.ts
More file actions
163 lines (152 loc) · 5.73 KB
/
useDragSort.ts
File metadata and controls
163 lines (152 loc) · 5.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// 表格 行拖拽 + 列拖拽功能
import {
SetupContext, computed, toRefs, ref, watch,
} from '@vue/composition-api';
import Sortable, { SortableEvent, SortableOptions } from 'sortablejs';
import get from 'lodash/get';
import { TableRowData, TdPrimaryTableProps, DragSortContext } from '../type';
import useClassName from './useClassName';
import log from '../../_common/js/log';
import swapDragArrayElement from '../../_common/js/utils/swapDragArrayElement';
/**
* TODO:
* 1. 同时支持行拖拽和列拖拽,此时 dragSort 扩展为支持数组即可
* 2. 支持多级表头场景下的列拖拽排序,此时需要将叶子结点 tColumns 作为参数传入。tColumns 已在 useMultiHeader 中计算出来
* 3. 优化列拖拽排序样式(优先级不高,可以慢慢来)
* @param props
* @param context
* @returns
*/
export default function useDragSort(props: TdPrimaryTableProps, context: SetupContext) {
const {
sortOnRowDraggable, dragSort, columns, data,
} = toRefs(props);
const { tableDraggableClasses, tableBaseClass } = useClassName();
const primaryTableRef = ref(null);
// 判断是否有拖拽列
const dragCol = computed(() => columns.value.find((item) => item.colKey === 'drag'));
// 行拖拽判断条件
const isRowDraggable = computed(() => sortOnRowDraggable.value || dragSort.value === 'row');
// 行手柄列拖拽判断条件
const isRowHandlerDraggable = computed(() => ['drag-col', 'row-handler'].includes(dragSort.value) && !!dragCol.value);
// 列拖拽排序,待开发
const isColDraggable = computed(() => dragSort.value === 'col');
// 行拖拽排序,存储上一次的变化结果
const lastRowList = ref([]);
// 列拖拽排序,存储上一次的变化结果
const lastColList = ref([]);
if (dragSort.value === 'drag-col') {
log.error('Table', "dragSort='drag-col' is going to be deprecated, please use dragSort='col' instead.");
}
if (props.sortOnRowDraggable) {
log.error('Table', "`sortOnRowDraggable` is going to be deprecated, please use dragSort='row' instead.");
}
watch(
data,
(data) => {
lastRowList.value = data?.map((item) => get(item, props.rowKey));
},
{ immediate: true },
);
watch(
columns,
(columns) => {
lastColList.value = columns || [];
},
{ immediate: true },
);
// 行拖拽排序
const registerRowDragEvent = (element: HTMLDivElement): void => {
if (!isRowHandlerDraggable.value && !isRowDraggable.value) return;
const dragContainer = element?.querySelector('tbody');
if (!dragContainer) {
console.error('tbody does not exist.');
return null;
}
// 拖拽实例
let dragInstanceTmp: Sortable = null;
const baseOptions: SortableOptions = {
animation: 150,
...props.dragSortOptions,
ghostClass: tableDraggableClasses.ghost,
chosenClass: tableDraggableClasses.chosen,
dragClass: tableDraggableClasses.dragging,
onEnd(evt: SortableEvent) {
// 处理受控:拖拽列表恢复原始排序
dragInstanceTmp?.sort(lastRowList.value);
const { oldIndex: currentIndex, newIndex: targetIndex } = evt;
const params: DragSortContext<TableRowData> = {
currentIndex,
current: data.value[currentIndex],
targetIndex,
target: data.value[targetIndex],
currentData: swapDragArrayElement(props.data, currentIndex, targetIndex),
e: evt,
sort: 'row',
};
props.onDragSort?.(params);
// Vue3 ignore next line
context.emit('drag-sort', params);
},
};
if (isRowDraggable.value) {
dragInstanceTmp = new Sortable(dragContainer, { ...baseOptions });
} else {
dragInstanceTmp = new Sortable(dragContainer, {
...baseOptions,
handle: `.${tableDraggableClasses.handle}`,
});
}
lastRowList.value = dragInstanceTmp.toArray();
};
// 列拖拽排序
const registerColDragEvent = (tableElement: HTMLElement) => {
if (!isColDraggable.value || !tableElement) return;
// 拖拽实例
let dragInstanceTmp: Sortable = null;
const options: SortableOptions = {
animation: 150,
...props.dragSortOptions,
dataIdAttr: 'data-colkey',
direction: 'vertical',
ghostClass: tableDraggableClasses.ghost,
chosenClass: tableDraggableClasses.chosen,
dragClass: tableDraggableClasses.dragging,
handle: `.${tableBaseClass.thCellInner}`,
onEnd: (evt: SortableEvent) => {
// 处理受控:拖拽列表恢复原始排序,等待外部数据 data 变化,更新最终顺序
dragInstanceTmp?.sort([...lastColList.value]);
const { oldIndex: currentIndex, newIndex: targetIndex } = evt;
const params: DragSortContext<TableRowData> = {
currentIndex,
current: columns.value[currentIndex],
targetIndex,
target: columns.value[targetIndex],
currentData: swapDragArrayElement(columns.value, currentIndex, targetIndex),
e: evt,
sort: 'col',
};
props.onDragSort?.(params);
// Vue3 ignore next line
context.emit('drag-sort', params);
},
};
const container = tableElement.querySelector('thead > tr') as HTMLDivElement;
dragInstanceTmp = new Sortable(container, options);
lastColList.value = dragInstanceTmp?.toArray();
};
function setDragSortPrimaryTableRef(primaryTableElement: any) {
primaryTableRef.value = primaryTableElement;
}
// 注册拖拽事件
watch([primaryTableRef], ([val]: [any]) => {
val?.$el && registerRowDragEvent(val?.$el);
val?.$el && registerColDragEvent(val?.$el);
});
return {
isRowDraggable,
isRowHandlerDraggable,
isColDraggable,
setDragSortPrimaryTableRef,
};
}