首页 > 解决方案 > 与角度叠加 cdk 全球定位策略和在灰色区域的任何位置放置元素有关的问题

问题描述

我正在学习教程并实现了拖放,但是我面临两个问题

  1. 关于使用新的 GlobalPositionStrategy(document); 在draggable 文件夹下的draggable-helper.directive.ts文件中,显示错误说明 Expected 0 arguments but got 1 ,因此我无法获得预期的结果,如此链接 https://stackblitz.com/edit/ draggable-part-6-4lwvqa?file=app/app.component.html

  2. 我可以拖放灰色区域中的框,但问题是,每次拖放时,我拖放的框都位于灰色区域的同一顶部、左侧位置。

期望盒子可以在灰色区域内的任何地方拖放(一旦我拖放,之后我就可以将盒子移动到任何地方,而期望盒子可以在灰色区域内的任何地方拖放)

dropzone.directive.ts有一个函数isEventInside我尝试调整它但无法解决问题(2)。

拖放如何工作的事件链是,在 hello.component 我们有输出事件 dragStart 和 drop,它们存在于draggable.directive.tsdropzone.directive.ts中。

Stackblitz 链接 https://stackblitz.com/edit/angular-1gjtab?file=src/app/hello.component.html

可拖动的.directive

import { Directive, EventEmitter, HostBinding, HostListener, Output, 
       ElementRef } from '@angular/core';

@Directive({
     selector: '[appDraggable],[appDroppable]'
 })
export class DraggableDirective {
@HostBinding('class.draggable') draggable = true;

 pointerId?: number;

@HostBinding('attr.touch-action') touchAction = 'none';

@Output() dragStart = new EventEmitter<PointerEvent>();
@Output() dragMove = new EventEmitter<PointerEvent>();
@Output() dragEnd = new EventEmitter<PointerEvent>();

@HostBinding('class.dragging') dragging = false;

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

dropzone.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 {

 @HostBinding('class.dropzone-activated') activated = false;
 @HostBinding('class.dropzone-entered') entered = false;

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

    this.activated = false;
    this.entered = false;
   }

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

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

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

你好组件

<div #parentparent id="toget" class="dropzone"
   [ngStyle]="{'width':'400px', 'border':'1px solid black', 'height':'340px'                   
   'margin-top':'120px'}" appMovableArea appDropzone 
   (drop)="move(currentBox, dropzone1)">

<div class="box" appMovable
    *ngFor="let existingZone of existingDroppedItemZoneIn"
    (dragStart)="currentBox = existingZone" 
    (dragEnd)="onDragEnd($event,box)" #childchild>
    {{ existingZone.main }}
</div>

<div class="box" *ngFor="let box of dropzone1" appDroppable 
  (dragStart)="currentBox = box" appMovable 
  (dragEnd)="onDragEnd($event,box)" #childchild>
    {{ box.dis.dis }}
</div>    
</div>

应用程序组件

<div *ngFor="let room of rooms"
      class="box"
      appDroppable
      (dragStart)="currentBox = room">
 {{ room.dis }}
 <div class="box box-helper" *appDraggableHelper>{{ room.dis }}</div>
</div>

<hello  [roomsFloorZone]='zonesToBePassed' 
        [currentBoxFloorZone]='currentBox'
        [existingDroppedItem] = 'droppedItem' 
        (floorToParent)="updateFloorRooms($event)"
        [ngStyle]="{'margin- top':'90px'}">
</hello>

droppable.directive

import { Directive, HostListener } from '@angular/core';
import { DroppableService } from './droppable.service';

@Directive({
 selector: '[appDroppable]'
})
export class DroppableDirective {

 constructor(private droppableService: DroppableService) { }

@HostListener('dragStart', ['$event'])
 onDragStart(event: PointerEvent): void {
 this.droppableService.onDragStart(event);
}

@HostListener('dragMove', ['$event'])
 onDragMove(event: PointerEvent): void {
 this.droppableService.onDragMove(event);
}

@HostListener('dragEnd', ['$event'])
 onDragEnd(event: PointerEvent): void {
 this.droppableService.onDragEnd(event);
}

}

标签: javascriptangularangular-cdk

解决方案


我不知道我是否正确。由于讨论很长,我开始了一个不同的答案......

用于 DnD 的两个不同 Stackblitz 版本以及来自 Angular 的不同版本。一对一的说法是使用 Angular 5.2.4,而不起作用的是使用 8.1.4。

我猜初始化应该是这样的

  private positionStrategy = new GlobalPositionStrategy();
...
 ngOnInit(): void {
    this.positionStrategy.attach(...);

正确使用请参考

我看到的另一个问题是 DnD 图像设置不正确。您需要设置它,因为 drop 已经是鼠标光标指向的位置。


推荐阅读