Voici celui que je l'ai écrit - il y a beaucoup de choses inutiles qui est là juste pour grincer chaque morceau de performance que possible tout en suivant également les meilleures pratiques angulaires - je vais le suivre avec un trimm ed/version simplifiée.
Ils ont tous les deux seulement besoin de la directive seule, pas de modifications/requêtes CSS ou html autres que l'ajout du sélecteur de directives à l'élément que vous voulez. Ils utilisent tous les deux translate3d plutôt que de changer la position du haut et du gauche, ce qui peut déclencher l'accélération du GPU sur certains navigateurs, mais même sans cela, il fonctionne généralement plus facilement que le changement de position. C'est ce que la transformation traduire a été faite pour - déplacer un élément par rapport à soi-même. Ils utilisent tous deux HostBinding pour se lier à la propriété, plutôt que d'accéder directement à un attribut nativeElement (qui couple inutilement la directive au DOM). Le second est sympa bc il ne nécessite pas de dépendances pour ElementRef ou Renderer2, mais il ajoute un écouteur always-on à l'objet document donc je l'utilise rarement, même si son aspect est plus propre.
J'utilise le premier parce qu'il n'ajoute que l'écouteur mousemove quand on clique sur le modal, et le supprime quand il n'est plus nécessaire. De plus, il exécute toutes les fonctions de mouvement en dehors de l'angle de sorte que glisser le modal ne déclenchera pas constamment la détection de changement angulaire sans raison (rien dans la boîte modale ne changera pendant qu'il est traîné, je suppose, donc inutile de vérifier). Et puis, comme la plupart de mes modaux sont créés dynamiquement et détruits lorsqu'ils sont fermés, ils peuvent également supprimer les écouteurs d'événements dans ce cas. J'injecte elementref pour que je puisse obtenir une référence à l'élément parent de la directive qui nécessite l'accès à nativeElement, mais je ne modifie pas les valeurs, juste en les lisant une fois pour obtenir une référence. Je pense donc que sa pardonnable dans la doctrine angulaire: p
import { Directive,
Input,
NgZone,
Renderer2,
HostListener,
HostBinding,
OnInit,
ElementRef } from '@angular/core';
class Position {
x: number; y: number;
constructor (x, y) { this.x = x; this.y = y; }
};
@Directive({
selector: '[lt-drag]'
})
export class LtDragDirective {
private allowDrag = true;
private moving = false;
private origin = null;
// for adding/detaching mouse listeners dynamically so they're not *always* listening
private moveFunc: Function;
private clickFunc: Function;
constructor(private el:ElementRef,
private zone: NgZone,
private rend: Renderer2) {}
@Input('handle') handle: HTMLElement;
@HostBinding('style.transform') transform: string = 'translate3d(0,0,0)';
ngOnInit() {
let host = this.el.nativeElement.offsetParent;
// applies mousemove and mouseup listeners to the parent component, typically my app componennt window, I prefer doing it like this so I'm not binding to a window or document object
this.clickFunc = this.rend.listen(host, 'mouseup' ,()=>{
this.moving = false;
});
// uses ngzone to run moving outside angular for better performance
this.moveFunc = this.rend.listen(host, 'mousemove' ,($event)=>{
if (this.moving && this.allowDrag) {
this.zone.runOutsideAngular(()=>{
event.preventDefault();
this.moveTo($event.clientX, $event.clientY);
});
}
});
}
// detach listeners if host element is removed from DOM
ngOnDestroy() {
if (this.clickFunc) { this.clickFunc(); }
if (this.moveFunc) { this.moveFunc(); }
}
// parses css translate string for exact px position
private getPosition(x:number, y:number) : Position {
let transVal:string[] = this.transform.split(',');
let newX = parseInt(transVal[0].replace('translate3d(',''));
let newY = parseInt(transVal[1]);
return new Position(x - newX, y - newY);
}
private moveTo(x:number, y:number) : void {
if (this.origin) {
this.transform = this.getTranslate((x - this.origin.x), (y - this.origin.y));
}
}
private getTranslate(x:number,y:number) : string{
return 'translate3d('+x+'px,'+y+'px,0px)';
}
@HostListener('mousedown',['$event'])
onMouseDown(event: MouseEvent) {
if (event.button == 2 || (this.handle !== undefined && event.target !==
this.handle)) {
return;
}
else {
this.moving = true;
this.origin = this.getPosition(event.clientX, event.clientY);
}
}
}
version plus simple ci-dessous - si vous n'êtes pas intéressés à garder les écouteurs d'événements ouverts ou se lier à l'objet document
import { Directive,
Input,
HostListener,
HostBinding,
OnInit } from '@angular/core';
class Position {
x: number; y: number;
constructor (x, y) { this.x = x; this.y = y; }
};
@Directive({
selector: '[lt-drag]'
})
export class LtDragDirective {
private moving = false;
private origin = null;
constructor() {}
@Input('handle') handle: HTMLElement;
@HostBinding('style.transform') transform: string = 'translate3d(0,0,0)';
@HostListener('document:mousemove',[$event]) mousemove($event:MouseEvent) {
event.preventDefault();
this.moveTo($event.clientX, $event.clientY);
}
@HostListener('document:mouseup') mouseup() {
this.moving = false;
}
@HostListener('mousedown',['$event'])
onMouseDown(event: MouseEvent) {
if (event.button == 2 || (this.handle !== undefined && event.target !== this.handle)) {
return; // if handle was provided and not clicked, ignore
}
else {
this.moving = true;
this.origin = this.getPosition(event.clientX, event.clientY);
}
}
private getPosition(x:number, y:number) : Position {
let transVal:string[] = this.transform.split(',');
let newX = parseInt(transVal[0].replace('translate3d(',''));
let newY = parseInt(transVal[1]);
return new Position(x - newX, y - newY);
}
private moveTo(x:number, y:number) : void {
if (this.origin) {
this.transform = this.getTranslate((x - this.origin.x), (y -
this.origin.y));
}
}
private getTranslate(x:number,y:number) : string{
return 'translate3d('+x+'px,'+y+'px,0px)';
}
}
Merci, cela fonctionne:) Maintenant, j'ai juste besoin de comprendre pour obtenir le bon élément hôte :) – methgaard
Le composant racine ou le plus proche que vous pouvez l'obtenir est idéal, car il occupe généralement l'espace plein écran. Si le niveau de hiérarchie est différent de plusieurs niveaux, vous pouvez obtenir le ElementRef dans le composant de l'application et l'envoyer au modal avec un service :-) Ou simplement dire le visser et le lier au document – diopside