So implementieren Sie ein ziehbares Div in Angular 2 mit Rx
Ich habe versucht, ein ziehbares Div mit Angular 2 zum Laufen zu bringen. Ich verwende dieses Beispiel aus dem Angular2-Beispiel-Repo als Ausgangspunkt und passe den Code nur wirklich an, um das Entfernen der toRx()
Methode zu berücksichtigen . Der Code funktioniert, berücksichtigt jedoch keine mouseout
Ereignisse. Das heißt, wenn ich auf ein ziehbares Div klicke und die Maus langsam bewege, bewegt sich das Div mit der Maus. Wenn ich die Maus jedoch zu schnell bewege, mouseout
wird anstelle eines mousemove
Ereignisses ein Ereignis gesendet , und das Ziehen wird gestoppt.
Wie kann ich das Ziehen fortsetzen, nachdem die Maus so weit bewegt wurde, dass ein mouseout
Ereignis ausgelöst wird? Ich habe versucht, den mouseout
Ereignisstrom mit dem mousemove
einen zusammenzuführen, damit mouseout
Ereignisse wie mousemove
solche behandelt werden, aber das funktioniert nicht.
Ich verwende Angular 2.0.0-beta.12.
import {Component, Directive, HostListener, EventEmitter, ElementRef, OnInit} from 'angular2/core';
import {map, merge} from 'rxjs/Rx';
@Directive({
selector: '[draggable]'
})
export class Draggable implements OnInit {
mouseup = new EventEmitter();
mousedown = new EventEmitter();
mousemove = new EventEmitter();
mouseout = new EventEmitter();
@HostListener('mouseup', ['$event'])
onMouseup(event) {
this.mouseup.emit(event);
}
@HostListener('mousedown', ['$event'])
onMousedown(event) {
this.mousedown.emit(event);
return false; // Call preventDefault() on the event
}
@HostListener('mousemove', ['$event'])
onMousemove(event) {
this.mousemove.emit(event);
}
@HostListener('mouseout', ['$event'])
onMouseout(event) {
this.mouseout.emit(event);
return false; // Call preventDefault() on the event
}
constructor(public element: ElementRef) {
this.element.nativeElement.style.position = 'relative';
this.element.nativeElement.style.cursor = 'pointer';
map;
merge;
this.mousedrag = this.mousedown.map(event => {
return {
top: event.clientY - this.element.nativeElement.getBoundingClientRect().top
left: event.clientX - this.element.nativeElement.getBoundingClientRect().left,
};
})
.flatMap(
imageOffset => this.mousemove.merge(this.mouseout).map(pos => ({
top: pos.clientY - imageOffset.top,
left: pos.clientX - imageOffset.left
}))
.takeUntil(this.mouseup)
);
}
ngOnInit() {
this.mousedrag.subscribe({
next: pos => {
this.element.nativeElement.style.top = pos.top + 'px';
this.element.nativeElement.style.left = pos.left + 'px';
}
});
}
}
@Component({
selector: 'my-app',
template: `
<div draggable>
<h1>Hello, World!</h1>
</div>
`,
directives: [Draggable,],
})
export class AppComponent {
}
Ich fand die Antwort auf diese Frage in RxJs Wie mit Dokumentereignissen viel tun . Der Kern des Problems besteht darin, dass Mausereignisse nur an ein Element gesendet werden, wenn sich die Maus über diesem Element befindet. Wir möchten also, dass das mousedown
Ereignis auf ein bestimmtes Element beschränkt ist, aber wir müssen globale Ereignisse mousemove
und mouseup
Ereignisse verfolgen . Hier ist der neue Code. Beachten Sie die Verwendung des @HostListener
Dekorators an onMouseup
und geben Sie onMousemove
das Ziel als document:mouseup
und an document:mousemove
. Auf diese Weise werden die globalen Ereignisse in den Rx-Stream geleitet.
In der offiziellen Angular2-Dokumentation für HostListener wird diese target:eventName
Syntax nicht erwähnt , in dieser alten Dart-Dokumentation für 2.0.0-alpha.24 wird sie jedoch erwähnt. Es scheint immer noch in 2.0.0-beta.12 zu funktionieren.
@Directive({
selector: '[draggable]'
})
export class Draggable implements OnInit {
mouseup = new EventEmitter<MouseEvent>();
mousedown = new EventEmitter<MouseEvent>();
mousemove = new EventEmitter<MouseEvent>();
mousedrag: Observable<{top, left}>;
@HostListener('document:mouseup', ['$event'])
onMouseup(event: MouseEvent) {
this.mouseup.emit(event);
}
@HostListener('mousedown', ['$event'])
onMousedown(event: MouseEvent) {
this.mousedown.emit(event);
return false; // Call preventDefault() on the event
}
@HostListener('document:mousemove', ['$event'])
onMousemove(event: MouseEvent) {
this.mousemove.emit(event);
}
constructor(public element: ElementRef) {
this.element.nativeElement.style.position = 'relative';
this.element.nativeElement.style.cursor = 'pointer';
this.mousedrag = this.mousedown.map(event => {
return {
top: event.clientY - this.element.nativeElement.getBoundingClientRect().top
left: event.clientX - this.element.nativeElement.getBoundingClientRect().left,
};
})
.flatMap(
imageOffset => this.mousemove.map(pos => ({
top: pos.clientY - imageOffset.top,
left: pos.clientX - imageOffset.left
}))
.takeUntil(this.mouseup)
);
}
ngOnInit() {
this.mousedrag.subscribe({
next: pos => {
this.element.nativeElement.style.top = pos.top + 'px';
this.element.nativeElement.style.left = pos.left + 'px';
}
});
}
}