Skip to content

Commit f7e0f31

Browse files
crisbetowagnermaciel
authored andcommitted
perf(drag-drop): bind fewer touchmove listeners (#20404)
On touch devices we have to bind the `touchmove` event before dragging has started, because iOS Safari won't allow us to call `preventDefault` on it otherwise. We also bind another `touchmove` listener once dragging starts which is what is used for moving the elements around on the screen. These changes remove the dynamically-added `touchmove` listener and use the persistent one for everything instead. (cherry picked from commit 2b1d84e)
1 parent 7a4d94b commit f7e0f31

File tree

1 file changed

+20
-9
lines changed

1 file changed

+20
-9
lines changed

src/cdk/drag-drop/drag-drop-registry.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class DragDropRegistry<I, C> implements OnDestroy {
8383
this._ngZone.runOutsideAngular(() => {
8484
// The event handler has to be explicitly active,
8585
// because newer browsers make it passive by default.
86-
this._document.addEventListener('touchmove', this._preventDefaultWhileDragging,
86+
this._document.addEventListener('touchmove', this._persistentTouchmoveListener,
8787
activeCapturingEventOptions);
8888
});
8989
}
@@ -100,7 +100,7 @@ export class DragDropRegistry<I, C> implements OnDestroy {
100100
this.stopDragging(drag);
101101

102102
if (this._dragInstances.size === 0) {
103-
this._document.removeEventListener('touchmove', this._preventDefaultWhileDragging,
103+
this._document.removeEventListener('touchmove', this._persistentTouchmoveListener,
104104
activeCapturingEventOptions);
105105
}
106106
}
@@ -120,18 +120,12 @@ export class DragDropRegistry<I, C> implements OnDestroy {
120120

121121
if (this._activeDragInstances.size === 1) {
122122
const isTouchEvent = event.type.startsWith('touch');
123-
const moveEvent = isTouchEvent ? 'touchmove' : 'mousemove';
124-
const upEvent = isTouchEvent ? 'touchend' : 'mouseup';
125123

126124
// We explicitly bind __active__ listeners here, because newer browsers will default to
127125
// passive ones for `mousemove` and `touchmove`. The events need to be active, because we
128126
// use `preventDefault` to prevent the page from scrolling while the user is dragging.
129127
this._globalListeners
130-
.set(moveEvent, {
131-
handler: (e: Event) => this.pointerMove.next(e as TouchEvent | MouseEvent),
132-
options: activeCapturingEventOptions
133-
})
134-
.set(upEvent, {
128+
.set(isTouchEvent ? 'touchend' : 'mouseup', {
135129
handler: (e: Event) => this.pointerUp.next(e as TouchEvent | MouseEvent),
136130
options: true
137131
})
@@ -150,6 +144,15 @@ export class DragDropRegistry<I, C> implements OnDestroy {
150144
options: activeCapturingEventOptions
151145
});
152146

147+
// We don't have to bind a move event for touch drag sequences, because
148+
// we already have a persistent global one bound from `registerDragItem`.
149+
if (!isTouchEvent) {
150+
this._globalListeners.set('mousemove', {
151+
handler: (e: Event) => this.pointerMove.next(e as MouseEvent),
152+
options: activeCapturingEventOptions
153+
});
154+
}
155+
153156
this._ngZone.runOutsideAngular(() => {
154157
this._globalListeners.forEach((config, name) => {
155158
this._document.addEventListener(name, config.handler, config.options);
@@ -190,6 +193,14 @@ export class DragDropRegistry<I, C> implements OnDestroy {
190193
}
191194
}
192195

196+
/** Event listener for `touchmove` that is bound even if no dragging is happening. */
197+
private _persistentTouchmoveListener = (event: TouchEvent) => {
198+
if (this._activeDragInstances.size) {
199+
event.preventDefault();
200+
this.pointerMove.next(event);
201+
}
202+
}
203+
193204
/** Clears out the global event listeners from the `document`. */
194205
private _clearGlobalListeners() {
195206
this._globalListeners.forEach((config, name) => {

0 commit comments

Comments
 (0)