Skip to content

Commit f0432c9

Browse files
authored
新增拖拽2.0组件 (#1803)
1 parent 2907c9c commit f0432c9

25 files changed

+7543
-154
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { App } from 'vue';
2+
import { DragDropService } from './src/drag-drop.service';
3+
import { default as Draggable } from './src/draggable.directive';
4+
import { default as Droppable } from './src/droppable.directive';
5+
import { default as Sortable } from './src/sortable.directive';
6+
import { default as DropScrollEnhanced, DropScrollEnhancedSide } from './src/drop-scroll-enhance.directive';
7+
import { default as BatchDraggable } from './src/batch-draggable.directive';
8+
import { default as DragPreview } from './src/drag-preview.directive';
9+
import { DragPreviewTemplate } from './src/drag-preview.component';
10+
import { default as DragPreviewCloneDomRef } from './src/drag-preview-clone-dom-ref.component';
11+
import { default as useDragDropSort } from './src/sync';
12+
13+
export * from './src/drag-drop.service';
14+
export * from './src/draggable.directive';
15+
export * from './src/droppable.directive';
16+
export * from './src/sortable.directive';
17+
export * from './src/drop-scroll-enhance.directive';
18+
export * from './src/batch-draggable.directive';
19+
export * from './src/drag-preview.component';
20+
export * from './src/drag-preview.directive';
21+
export * from './src/drag-preview-clone-dom-ref.component';
22+
export * from './src/sync';
23+
24+
export { Draggable, Droppable, Sortable, DropScrollEnhanced };
25+
26+
export default {
27+
title: 'DragDrop 2.0 拖拽',
28+
category: '通用',
29+
status: '100%',
30+
install(app: App): void {
31+
app.directive('dDraggable', Draggable);
32+
app.directive('dDroppable', Droppable);
33+
app.directive('dSortable', Sortable);
34+
app.directive('dDropScrollEnhanced', DropScrollEnhanced);
35+
app.directive('dDropScrollEnhancedSide', DropScrollEnhancedSide);
36+
app.directive('dDraggableBatchDrag', BatchDraggable);
37+
app.directive('dDragPreview', DragPreview);
38+
app.component('DDragPreviewTemplate', DragPreviewTemplate);
39+
app.component(DragPreviewCloneDomRef.name, DragPreviewCloneDomRef);
40+
app.provide(DragDropService.TOKEN, new DragDropService());
41+
app.use(useDragDropSort);
42+
},
43+
};
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import { EventEmitter } from './preserve-next-event-emitter';
2+
import { DragDropService } from './drag-drop.service';
3+
import { NgDirectiveBase, NgSimpleChanges } from './directive-base';
4+
import { DraggableDirective } from './draggable.directive';
5+
import { DirectiveBinding } from 'vue';
6+
import { injectFromContext } from './utils';
7+
export type BatchDragStyle = 'badge' | 'stack' | string;
8+
9+
export interface IBatchDraggableBinding {
10+
batchDragGroup?: string;
11+
batchDragActive?: boolean;
12+
batchDragLastOneAutoActiveEventKeys?: Array<string>;
13+
batchDragStyle?: string | Array<string>;
14+
}
15+
export interface IBatchDraggableListener {
16+
'@batchDragActiveEvent'?: (_: any) => void;
17+
}
18+
19+
export class BatchDraggableDirective extends NgDirectiveBase<IBatchDraggableBinding, IBatchDraggableListener> {
20+
static INSTANCE_KEY = '__vueDevuiBatchDraggableDirectiveInstance';
21+
batchDragGroup = 'default';
22+
batchDragActive = false;
23+
batchDragLastOneAutoActiveEventKeys = ['ctrlKey'];
24+
batchDragStyle: Array<BatchDragStyle> = ['badge', 'stack'];
25+
batchDragActiveEvent = new EventEmitter<any>();
26+
dragData?: any;
27+
needToRestore = false;
28+
29+
constructor(private draggable: DraggableDirective, private dragDropService: DragDropService) {
30+
super();
31+
this.draggable.batchDraggable = this;
32+
}
33+
34+
ngOnInit() {
35+
this.initDragDataByIdentity();
36+
}
37+
38+
ngOnDestroy() {
39+
this.draggable.batchDraggable = undefined;
40+
if (this.dragData) {
41+
if (this.dragData.draggable === this.draggable) {
42+
this.dragData.draggable = undefined;
43+
if (!this.dragData.identity) {
44+
this.removeFromBatchGroup();
45+
}
46+
}
47+
}
48+
}
49+
50+
ngOnChanges(changes: NgSimpleChanges): void {
51+
if (changes['batchDragActive']) {
52+
if (!this.initDragDataByIdentity()) {
53+
if (this.batchDragActive) {
54+
if (!this.dragData && this.allowAddToBatchGroup()) {
55+
this.addToBatchGroup();
56+
}
57+
} else {
58+
this.removeFromBatchGroup();
59+
}
60+
}
61+
}
62+
}
63+
ngAfterViewInit() {
64+
if (this.needToRestore) {
65+
this.restoreDragDataViewAfterViewInit();
66+
this.needToRestore = false;
67+
}
68+
}
69+
initDragDataByIdentity() {
70+
const dragData = this.findInBatchDragDataByIdentities();
71+
if (dragData) {
72+
if (this.batchDragActive) {
73+
if (!this.dragData) {
74+
this.addToBatchGroup(dragData);
75+
this.registerRestoreDragDataViewAfterViewInitWhiteDragging();
76+
}
77+
} else {
78+
this.removeFromBatchGroup(dragData);
79+
}
80+
}
81+
return dragData;
82+
}
83+
84+
registerRestoreDragDataViewAfterViewInitWhiteDragging() {
85+
if (
86+
this.dragDropService.draggedEl &&
87+
this.dragDropService.draggedElIdentity &&
88+
this.dragDropService.draggedEl !== this.draggable.el.nativeElement
89+
) {
90+
this.needToRestore = true;
91+
}
92+
}
93+
restoreDragDataViewAfterViewInit() {
94+
const draggable = this.draggable;
95+
if (draggable.originPlaceholder && draggable.originPlaceholder.show !== false) {
96+
draggable.insertOriginPlaceholder(true, false);
97+
}
98+
draggable.el.nativeElement.style.display = 'none';
99+
}
100+
101+
allowAddToBatchGroup() {
102+
if (!this.dragDropService.batchDragGroup) {
103+
return true;
104+
} else {
105+
return this.batchDragGroup === this.dragDropService.batchDragGroup;
106+
}
107+
}
108+
addToBatchGroup(dragData?: any) {
109+
this.dragDropService.batchDragGroup = this.dragDropService.batchDragGroup || this.batchDragGroup;
110+
if (dragData) {
111+
dragData.draggable = this.draggable;
112+
dragData.dragData = this.draggable.dragData;
113+
this.dragData = dragData;
114+
} else {
115+
this.dragData = this.dragData || {
116+
identity: this.draggable.dragIdentity || undefined,
117+
draggable: this.draggable,
118+
dragData: this.draggable.dragData,
119+
};
120+
this.dragDropService.batchDragData = this.addToArrayIfNotExist(this.dragDropService.batchDragData!, this.dragData);
121+
}
122+
}
123+
removeFromBatchGroup(dragData?: any) {
124+
this.deleteFromArrayIfExist(this.dragDropService.batchDragData!, dragData || this.dragData);
125+
this.dragData = undefined;
126+
if (!(this.dragDropService.batchDragData && this.dragDropService.batchDragData.length)) {
127+
this.dragDropService.batchDragGroup = undefined;
128+
}
129+
}
130+
131+
private addToArrayIfNotExist(array: any[], target: any) {
132+
array = array || [];
133+
if (array.indexOf(target) === -1) {
134+
array.push(target);
135+
}
136+
return array;
137+
}
138+
139+
private deleteFromArrayIfExist(array: any[], target: any) {
140+
if (!array) {
141+
return;
142+
}
143+
if (array.length > 0) {
144+
const index = array.indexOf(target);
145+
if (index > -1) {
146+
array.splice(index, 1);
147+
}
148+
}
149+
return array;
150+
}
151+
152+
private findInBatchDragDataByIdentities() {
153+
if (!this.draggable.dragIdentity) {
154+
return null;
155+
} else if (!this.dragDropService.batchDragData) {
156+
return undefined;
157+
} else {
158+
return this.dragDropService.batchDragData.filter((dragData) => dragData.identity === this.draggable.dragIdentity).pop();
159+
}
160+
}
161+
162+
active() {
163+
this.batchDragActiveEvent.emit({ el: this.draggable.el.nativeElement, data: this.draggable.dragData });
164+
}
165+
166+
public updateDragData() {
167+
// 选中状态才更新
168+
if (!this.dragData) {
169+
return;
170+
}
171+
// 需要维持内存地址不变
172+
Object.assign(this.dragData, {
173+
identity: this.draggable.dragIdentity || undefined,
174+
draggable: this.draggable,
175+
dragData: this.draggable.dragData,
176+
});
177+
}
178+
}
179+
180+
export default {
181+
mounted(el: HTMLElement & { [props: string]: any }, binding: DirectiveBinding<IBatchDraggableBinding & IBatchDraggableListener>, vNode) {
182+
const context = vNode['ctx'].provides;
183+
const dragDropService = injectFromContext(DragDropService.TOKEN, context) as DragDropService;
184+
const draggableDirective = injectFromContext(DraggableDirective.TOKEN, context) as DraggableDirective;
185+
const batchDraggableDirective = (el[BatchDraggableDirective.INSTANCE_KEY] = new BatchDraggableDirective(
186+
draggableDirective,
187+
dragDropService
188+
));
189+
batchDraggableDirective.setInput(binding.value);
190+
batchDraggableDirective.mounted();
191+
batchDraggableDirective.ngOnInit?.();
192+
setTimeout(() => {
193+
batchDraggableDirective.ngAfterViewInit?.();
194+
}, 0);
195+
},
196+
updated(el: HTMLElement & { [props: string]: any }, binding: DirectiveBinding<IBatchDraggableBinding & IBatchDraggableListener>) {
197+
const batchDraggableDirective = el[BatchDraggableDirective.INSTANCE_KEY] as BatchDraggableDirective;
198+
batchDraggableDirective.updateInput(binding.value, binding.oldValue!);
199+
},
200+
beforeUnmount(el: HTMLElement & { [props: string]: any }) {
201+
const batchDraggableDirective = el[BatchDraggableDirective.INSTANCE_KEY] as BatchDraggableDirective;
202+
batchDraggableDirective.ngOnDestroy?.();
203+
},
204+
};

0 commit comments

Comments
 (0)