由于在同一元素的多个指令中使用相同的鼠标事件,指令没有响应 [英] Directive not responding due to same mouse events being used in multiple directives on same element

查看:21
本文介绍了由于在同一元素的多个指令中使用相同的鼠标事件,指令没有响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

在添加resize指令之前,框只能在灰色区域内移动,但是添加resize指令后,当我们调整大小时,框开始移出灰色区域,问题是框不应移出灰色区域调整大小后的区域

Stackblitz 链接

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

hello.component.html [ 将盒子和指令应用到盒子上 ]

<div *ngFor="let box of dropzone1"可投放的(dragStart)="currentBox = box"应用可移动调整大小>{{ box.dis }}

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

<块引用>

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

import { 指令、ElementRef、EventEmitter、HostBinding、HostListener、OnInit, Output, SkipSelf } from '@angular/core';从 './droppable.service' 导入 { DroppableService };@指示({选择器:'[appDropzone]',提供者:[DroppableService]})导出类 DropzoneDirective 实现 OnInit {@Output() drop = new EventEmitter();@Output() remove = new EventEmitter();私有 clientRect: ClientRect;构造函数(@SkipSelf() private allDroppableService: DroppableService,私有内部DroppableService:DroppableService,私有元素:ElementRef) { }ngOnInit(): 无效 {this.allDroppableService.dragStart$.subscribe(() =>this.onDragStart());this.allDroppableService.dragEnd$.subscribe(event =>this.onDragEnd(事件));this.allDroppableService.dragMove$.subscribe(event => {如果(this.isEventInside(事件)){this.onPointerEnter();} 别的 {this.onPointerLeave();}});this.innerDroppableService.dragStart$.subscribe(() =>this.onInnerDragStart());this.innerDroppableService.dragEnd$.subscribe(event =>this.onInnerDragEnd(事件));}私有 onPointerEnter(): void {如果(!this.activated){返回;}this.entered = true;}私有 onPointerLeave(): void {如果(!this.activated){返回;}this.entered = false;}私人 onDragStart(): void {this.clientRect = this.element.nativeElement.getBoundingClientRect();this.activated = true;}私人 onDragEnd(事件:PointerEvent):无效{如果(!this.activated){返回;}如果(this.entered){this.drop.emit(事件);}}私人 onInnerDragStart() {this.activated = true;this.entered = true;}私人 onInnerDragEnd(事件:PointerEvent){如果 (!this.entered) {this.remove.emit(事件);}}私人 isEventInside(事件:PointerEvent){返回 event.clientX >= this.clientRect.left &&event.clientX <= this.clientRect.right &&event.clientY >= this.clientRect.top &&event.clientY <= this.clientRect.bottom;}}

<块引用>

然后在(dragStart)输出事件发射器上,它存在于draggable指令[appDraggable]中,它监听pointerdown事件

import { Directive, EventEmitter, HostBinding, HostListener, Output,ElementRef } 来自'@angular/core';@指示({选择器:'[appDraggable],[appDroppable]'})导出类 DraggableDirective {@Output() dragStart = new EventEmitter();@Output() dragMove = new EventEmitter();@Output() dragEnd = new EventEmitter();构造函数(公共元素:ElementRef){}@HostListener('pointerdown', ['$event'])onPointerDown(事件:PointerEvent):无效{如果(事件按钮!== 0){返回;}this.pointerId = event.pointerId;this.dragging = true;this.dragStart.emit(事件);}@HostListener('document:pointermove', ['$event'])onPointerMove(事件:PointerEvent):无效{if (!this.dragging || event.pointerId !== this.pointerId) {返回;}this.dragMove.emit(事件);}@HostListener('document:pointercancel', ['$event'])@HostListener('document:pointerup', ['$event'])onPointerUp(事件:PointerEvent):无效{if (!this.dragging || event.pointerId !== this.pointerId) {返回;}this.dragging = false;this.dragEnd.emit(事件);}}

<块引用>

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

import { Directive, ElementRef, HostBinding, HostListener, Input } from'@角度/核心';从 './draggable.directive' 导入 { DraggableDirective };从@angular/platform-b​​rowser"导入 { DomSanitizer, SafeStyle };接口位置{x:数量;y:数量;}@指示({选择器:'[appMovable]'})导出类 MovableDirective 扩展 DraggableDirective {@HostBinding('style.transform') get transform(): SafeStyle {返回 this.sanitizer.bypassSecurityTrustStyle(`translateX(${this.position.x}px) translateY(${this.position.y}px)`);}@HostBinding('class.movable') 可移动 = true;位置:位置 = {x: 0, y: 0};私人 startPosition:位置;@Input('appMovableReset') reset = false;构造函数(私有消毒剂:DomSanitizer,公共元素:ElementRef){超级(元素);}@HostListener('dragStart', ['$event'])onDragStart(事件:PointerEvent){this.startPosition = {x: event.clientX - this.position.x,y: event.clientY - this.position.y}}@HostListener('dragMove', ['$event'])onDragMove(事件:PointerEvent){this.position.x = event.clientX - this.startPosition.x;this.position.y = event.clientY - this.startPosition.y;}@HostListener('dragEnd', ['$event'])onDragEnd(事件:指针事件){如果(this.reset){this.position = {x: 0, y: 0};}}}

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

解决方案

你可以做的一个小技巧是将 'resizing' 类添加到 resize 指令中的元素,并检查该类是否存在于draggable 指令(如果存在)不使其可拖动.我无法获取您的代码,因为它太难了.我不知道你为什么把它弄得这么复杂.

I have a feature where box can be dragged and dropped into the grey area(Please refer to the stackblitz link) Once the box is dragged and dropped , the box can only be moved within the grey area by clicking on the pink color of the box.

Resizing functionality has also been added, so the box can be resized.

Before resize directive was added the box can only be moved within grey area but after adding adding the resize directive when we resize, the box starts moving out of the grey area , the issue is the box should not move out of the grey area when resizing is done

Stackblitz link

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

hello.component.html [ has the box and directives applied on the box ]

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

where the box has (dragStart) output event emitter which is bound to draggable directive([appDroppable + draggable] and for the move functionality appMovable, appMovableArea directives are there) .And the events are shared among directives using Droppable.service.ts

The (drop) is an output event emitter applied on grey area using dropzone[appDropzone] directive

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;
  }
}

Then on the box (dragStart) output event emitter which is present indraggable directive[appDraggable] which listens for pointerdown events

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);
    }
   }

Movable directive for maintaining move inside the grey area which in turn uses calculation based from movable-area directive

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};
 }
 }
}

The resize directive is also present in the stackblitz link. And styles for resize directive are present in styles.css

解决方案

One small hack you can do is add 'resizing' class to the element in resize directive and check whether that class is present in draggable directive if present do not make it draggable. I can't get your code because it's so difficult. I don't know why you made this so complex.

这篇关于由于在同一元素的多个指令中使用相同的鼠标事件,指令没有响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆