mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(drag-drop): prevent mouse wheel scrolling while dragging (#13524)
Prevents users from scrolling using the mouse wheel while an item is being dragged. This is a temporary measure until we have a solution to auto-scrolling while dragging, as well as to avoid having to measure the page for every pixel that the user has dragged. Fixes #13508.
This commit is contained in:
committed by
vivian-hu
parent
d0f4e7b220
commit
cd6da938ae
@@ -5,6 +5,7 @@ import {
|
||||
dispatchMouseEvent,
|
||||
createTouchEvent,
|
||||
dispatchTouchEvent,
|
||||
dispatchFakeEvent,
|
||||
} from '@angular/cdk/testing';
|
||||
import {DragDropRegistry} from './drag-drop-registry';
|
||||
import {DragDropModule} from './drag-drop-module';
|
||||
@@ -192,6 +193,15 @@ describe('DragDropRegistry', () => {
|
||||
expect(event.defaultPrevented).toBe(true);
|
||||
});
|
||||
|
||||
it('should not prevent the default `wheel` actions when nothing is being dragged', () => {
|
||||
expect(dispatchFakeEvent(document, 'wheel').defaultPrevented).toBe(false);
|
||||
});
|
||||
|
||||
it('should prevent the default `wheel` action when an item is being dragged', () => {
|
||||
registry.startDragging(testComponent.dragItems.first, createMouseEvent('mousedown'));
|
||||
expect(dispatchFakeEvent(document, 'wheel').defaultPrevented).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -43,7 +43,7 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
|
||||
private _activeDragInstances = new Set<I>();
|
||||
|
||||
/** Keeps track of the event listeners that we've bound to the `document`. */
|
||||
private _globalListeners = new Map<'touchmove' | 'mousemove' | 'touchend' | 'mouseup', {
|
||||
private _globalListeners = new Map<'touchmove' | 'mousemove' | 'touchend' | 'mouseup' | 'wheel', {
|
||||
handler: PointerEventHandler,
|
||||
options?: AddEventListenerOptions | boolean
|
||||
}>();
|
||||
@@ -81,10 +81,13 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
|
||||
registerDragItem(drag: I) {
|
||||
this._dragInstances.add(drag);
|
||||
|
||||
// The `touchmove` event gets bound once, ahead of time, because WebKit
|
||||
// won't preventDefault on a dynamically-added `touchmove` listener.
|
||||
// See https://bugs.webkit.org/show_bug.cgi?id=184250.
|
||||
if (this._dragInstances.size === 1) {
|
||||
this._ngZone.runOutsideAngular(() => {
|
||||
// The event handler has to be explicitly active, because
|
||||
// newer browsers make it passive by default.
|
||||
// The event handler has to be explicitly active,
|
||||
// because newer browsers make it passive by default.
|
||||
this._document.addEventListener('touchmove', this._preventScrollListener,
|
||||
activeCapturingEventOptions);
|
||||
});
|
||||
@@ -135,12 +138,22 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
|
||||
.set(upEvent, {
|
||||
handler: e => this.pointerUp.next(e),
|
||||
options: true
|
||||
})
|
||||
.forEach((config, name) => {
|
||||
this._ngZone.runOutsideAngular(() => {
|
||||
this._document.addEventListener(name, config.handler, config.options);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(crisbeto): prevent mouse wheel scrolling while
|
||||
// dragging until we've set up proper scroll handling.
|
||||
if (!isTouchEvent) {
|
||||
this._globalListeners.set('wheel', {
|
||||
handler: this._preventScrollListener,
|
||||
options: activeCapturingEventOptions
|
||||
});
|
||||
}
|
||||
|
||||
this._ngZone.runOutsideAngular(() => {
|
||||
this._globalListeners.forEach((config, name) => {
|
||||
this._document.addEventListener(name, config.handler, config.options);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,11 +186,9 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener used to prevent `touchmove` events while the element is being dragged.
|
||||
* This gets bound once, ahead of time, because WebKit won't preventDefault on a
|
||||
* dynamically-added `touchmove` listener. See https://bugs.webkit.org/show_bug.cgi?id=184250.
|
||||
* Listener used to prevent `touchmove` and `wheel` events while the element is being dragged.
|
||||
*/
|
||||
private _preventScrollListener = (event: TouchEvent) => {
|
||||
private _preventScrollListener = (event: Event) => {
|
||||
if (this._activeDragInstances.size) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user