首页 > 解决方案 > 由于在同一元素上的多个指令中使用了相同的鼠标事件,指令没有响应

问题描述

我有一个可以将盒子拖放到灰色区域的功能(请参阅stackblitz链接)一旦盒子被拖放,盒子只能通过点击盒子的粉红色在灰色区域内移动.

还添加了调整大小的功能,因此可以调整框的大小。

在添加resize指令之前,盒子只能在灰色区域内移动,但是在我们调整大小时添加resize指令后,盒子开始移出灰色区域,问题是盒子在调整大小时不应该移出灰色区域已经完成了

Stackblitz 链接

https://stackblitz.com/edit/angular-rgeq2p?file=src/app/hello.component.html

hello.component.html [在盒子上应用了盒子和指令]

<div appMovableArea appDropzone (drop)="move(currentBox, dropzone1)">
<div *ngFor="let box of dropzone1"
      appDroppable
     (dragStart)="currentBox = box"
      appMovable
      resize>
    {{ box.dis }}
</div>
</div>

盒子有 (dragStart) 输出事件发射器,它绑定到可拖动指令([appDroppable + draggable] 并且对于移动功能 appMovable,appMovableArea 指令在那里)。并且使用 Droppable.service.ts 在指令之间共享事件

( drop)是使用 dropzone [ appDropzone ] 指令应用于灰色区域的输出事件发射器

import { Directive, ElementRef, EventEmitter, HostBinding, HostListener, 
    OnInit, Output, SkipSelf } from '@angular/core';
import { DroppableService } from './droppable.service';

@Directive({
     selector: '[appDropzone]',
     providers: [DroppableService]
    })
export class DropzoneDirective implements OnInit {

     @Output() drop = new EventEmitter<PointerEvent>();
     @Output() remove = new EventEmitter<PointerEvent>();
     private clientRect: ClientRect;

constructor(@SkipSelf() private allDroppableService: DroppableService,
              private innerDroppableService: DroppableService,
              private element: ElementRef) { }

ngOnInit(): void {
        this.allDroppableService.dragStart$.subscribe(() => 
        this.onDragStart());
        this.allDroppableService.dragEnd$.subscribe(event => 
        this.onDragEnd(event));

        this.allDroppableService.dragMove$.subscribe(event => {
          if (this.isEventInside(event)) {
        this.onPointerEnter();
      } else {
        this.onPointerLeave();
      }
     });
        this.innerDroppableService.dragStart$.subscribe(() => 
        this.onInnerDragStart());
        this.innerDroppableService.dragEnd$.subscribe(event => 
        this.onInnerDragEnd(event));
}

private onPointerEnter(): void {
     if (!this.activated) {
      return;
     }
     this.entered = true;
     }

private onPointerLeave(): void {
        if (!this.activated) {
         return;
      }
     this.entered = false;
     }

private onDragStart(): void {
       this.clientRect = this.element.nativeElement.getBoundingClientRect();
       this.activated = true;
      }

private onDragEnd(event: PointerEvent): void {
        if (!this.activated) {
         return;
      }
      if (this.entered) {
        this.drop.emit(event);
      }
     }

private onInnerDragStart() {
    this.activated = true;
    this.entered = true;
    }

private onInnerDragEnd(event: PointerEvent) {
    if (!this.entered) {
      this.remove.emit(event);
    }
  }

private isEventInside(event: PointerEvent) {
    return event.clientX >= this.clientRect.left &&
      event.clientX <= this.clientRect.right &&
      event.clientY >= this.clientRect.top &&
      event.clientY <= this.clientRect.bottom;
  }
}

然后在可拖动指令 [ appDraggable ] 中存在的框(dragStart)输出事件发射器上,它侦听指针向下事件

import { Directive, EventEmitter, HostBinding, HostListener, Output, 
ElementRef } from '@angular/core';
@Directive({
 selector: '[appDraggable],[appDroppable]'
})
export class DraggableDirective {
 @Output() dragStart = new EventEmitter<PointerEvent>();
 @Output() dragMove = new EventEmitter<PointerEvent>();
 @Output() dragEnd = new EventEmitter<PointerEvent>();

 constructor(public element: ElementRef) {}

 @HostListener('pointerdown', ['$event'])
   onPointerDown(event: PointerEvent): void {
    if (event.button !== 0) {
    return;
   }
   this.pointerId = event.pointerId;
   this.dragging = true;
   this.dragStart.emit(event); 
   }

 @HostListener('document:pointermove', ['$event'])
    onPointerMove(event: PointerEvent): void {
     if (!this.dragging || event.pointerId !== this.pointerId) {
     return;
    } 
    this.dragMove.emit(event);
    }

 @HostListener('document:pointercancel', ['$event'])
 @HostListener('document:pointerup', ['$event'])
     onPointerUp(event: PointerEvent): void {
    if (!this.dragging || event.pointerId !== this.pointerId) {
      return;
    }
    this.dragging = false;
    this.dragEnd.emit(event);
    }
   }

用于在灰色区域内保持移动的可移动指令,而灰色区域又使用基于可移动区域指令的计算

import { Directive, ElementRef, HostBinding, HostListener, Input } from 
'@angular/core';
import { DraggableDirective } from './draggable.directive';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';

interface Position {
 x: number;
 y: number;
}

@Directive({
 selector: '[appMovable]'
})
export class MovableDirective extends DraggableDirective {
  @HostBinding('style.transform') get transform(): SafeStyle {
   return this.sanitizer.bypassSecurityTrustStyle(
  `translateX(${this.position.x}px) translateY(${this.position.y}px)`
  );
  }

  @HostBinding('class.movable') movable = true;
  position: Position = {x: 0, y: 0};
  private startPosition: Position;
  @Input('appMovableReset') reset = false;

constructor(private sanitizer: DomSanitizer, public element: ElementRef) {
   super(element);
 }

@HostListener('dragStart', ['$event'])
   onDragStart(event: PointerEvent) {
     this.startPosition = {
     x: event.clientX - this.position.x,
     y: event.clientY - this.position.y
 }
 }

@HostListener('dragMove', ['$event'])
   onDragMove(event: PointerEvent) {
    this.position.x = event.clientX - this.startPosition.x;
    this.position.y = event.clientY - this.startPosition.y;
 }

@HostListener('dragEnd', ['$event'])
   onDragEnd(event: PointerEvent) {
    if (this.reset) {
     this.position = {x: 0, y: 0};
 }
 }
}

resize 指令也出现在 stackblitz 链接中。调整大小指令的样式存在于 styles.css

标签: htmlcssangularangular-directive

解决方案


这是 Drag&Drop 指令的实现,抱歉无法修复您的代码,因为它与调整大小相同:

指示

@Directive({
  selector: '[draggable]'
})
class Draggable implements onInit {
    private element: HTMLElement;
    private handlerNode: HTMLElement;
    private data: {x: number, y: number};

    @Input('draggable')
    private handler: string;

    @HostListener('mousedown', ['$event'])
    mousedown(e) {
        if (e.target === this.handlerNode) {
            var rect = this.element.getBoundingClientRect();
            this.data = {
                x: e.clientX - rect.left,
                y: e.clientY - rect.top
            };
        } else {
            delete this.data;
        }
    }

    @HostListener('document:mouseup', ['$event'])
    mouseup(e) {
        delete this.data;
    }
    constructor(@Inject(ElementRef) element: ElementRef) {
        this.element = element.nativeElement;
    }
    ngOnInit() {
        this.element.classList.add('dragabble');
        this.handlerNode = this.element.querySelector(this.handler);
    }

    @HostListener('document:mousemove', ['$event'])
    onPointerMove(e: PointerEvent): void {
        if (this.data) {
            var x = e.clientX - this.data.x;
            var y = e.clientY - this.data.y;
            this.element.style.left = x + 'px';
            this.element.style.top = y + 'px';
        }
    }
}

CSS

.dragabble .handler {
    position: absolute;
    width: calc(100% - 12px);
    height: calc(100% - 12px);
    left: 6px;
    top: 6px;
}

模板

<div [resize]="toggle" style="left: 100px; top: 50px"
     [draggable]="'.handler'">
  <div class="handler">xxx</div>
</div>

演示:https ://codepen.io/jcubic/pen/wvwJNqQ?editors=0110


推荐阅读